napcat-cli 2.0.0__tar.gz
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.
- napcat_cli-2.0.0/.gitignore +74 -0
- napcat_cli-2.0.0/.gitmodules +3 -0
- napcat_cli-2.0.0/PKG-INFO +219 -0
- napcat_cli-2.0.0/README.md +208 -0
- napcat_cli-2.0.0/docs/HERMES_WAKE.md +95 -0
- napcat_cli-2.0.0/napcat_cli/__init__.py +3 -0
- napcat_cli-2.0.0/napcat_cli/cli.py +1834 -0
- napcat_cli-2.0.0/napcat_cli/daemon/__init__.py +1 -0
- napcat_cli-2.0.0/napcat_cli/daemon/schemas.py +470 -0
- napcat_cli-2.0.0/napcat_cli/daemon/watch.py +1994 -0
- napcat_cli-2.0.0/napcat_cli/data/SKILL.md +328 -0
- napcat_cli-2.0.0/napcat_cli/data/__init__.py +0 -0
- napcat_cli-2.0.0/napcat_cli/data/persona.md +155 -0
- napcat_cli-2.0.0/napcat_cli/data/references/mounting.md +90 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs-config.json +12 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs-fragment.json +473 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-friend-time.md +7 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-friend.md +7 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-friends.md +4 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-group-time.md +7 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-group.md +6 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-groups.md +5 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/agents-napcat.md +9 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/persona.md +155 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/skill-agents.md +42 -0
- napcat_cli-2.0.0/napcat_cli/data/skills-fs.d/skill-body.md +102 -0
- napcat_cli-2.0.0/napcat_cli/lib/__init__.py +1 -0
- napcat_cli-2.0.0/napcat_cli/lib/api.py +258 -0
- napcat_cli-2.0.0/napcat_cli/lib/config.py +105 -0
- napcat_cli-2.0.0/napcat_cli/lib/events.py +127 -0
- napcat_cli-2.0.0/napcat_cli/lib/events_sqlite.py +242 -0
- napcat_cli-2.0.0/napcat_cli/lib/message.py +156 -0
- napcat_cli-2.0.0/napcat_cli/setup_wizard.py +380 -0
- napcat_cli-2.0.0/napcat_cli/tui/__init__.py +1 -0
- napcat_cli-2.0.0/napcat_cli/tui/__main__.py +13 -0
- napcat_cli-2.0.0/napcat_cli/tui/api.py +158 -0
- napcat_cli-2.0.0/napcat_cli/tui/app.py +127 -0
- napcat_cli-2.0.0/napcat_cli/tui/chat_list.py +168 -0
- napcat_cli-2.0.0/napcat_cli/tui/chat_view.py +456 -0
- napcat_cli-2.0.0/napcat_cli/tui/styles.tcss +9 -0
- napcat_cli-2.0.0/napcat_cli/wake.py +51 -0
- napcat_cli-2.0.0/napcat_cli/wake_backend.py +390 -0
- napcat_cli-2.0.0/napcat_cli/wake_orchestrator.py +302 -0
- napcat_cli-2.0.0/napcat_cli/wake_presets.py +77 -0
- napcat_cli-2.0.0/persona.md +155 -0
- napcat_cli-2.0.0/pyproject.toml +40 -0
- napcat_cli-2.0.0/skills-fs-config.json +12 -0
- napcat_cli-2.0.0/tests/conftest.py +26 -0
- napcat_cli-2.0.0/tests/test_config.py +84 -0
- napcat_cli-2.0.0/tests/test_fs.py +73 -0
- napcat_cli-2.0.0/tests/test_setup.py +59 -0
- napcat_cli-2.0.0/tests/test_wake.py +58 -0
- napcat_cli-2.0.0/tests/test_wake_backend.py +183 -0
- napcat_cli-2.0.0/tests/test_wake_orchestrator.py +108 -0
- napcat_cli-2.0.0/tools/agents-md.json +10 -0
- napcat_cli-2.0.0/tools/gen_mounts.py +349 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# If you prefer the allow list template instead of the deny list, see community template:
|
|
2
|
+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
|
3
|
+
#
|
|
4
|
+
# Binaries for programs and plugins
|
|
5
|
+
*.exe
|
|
6
|
+
*.exe~
|
|
7
|
+
*.dll
|
|
8
|
+
*.so
|
|
9
|
+
*.dylib
|
|
10
|
+
|
|
11
|
+
# Test binary, built with `go test -c`
|
|
12
|
+
*.test
|
|
13
|
+
|
|
14
|
+
# Code coverage profiles and other test artifacts
|
|
15
|
+
*.out
|
|
16
|
+
coverage.*
|
|
17
|
+
*.coverprofile
|
|
18
|
+
profile.cov
|
|
19
|
+
|
|
20
|
+
# Dependency directories (remove the comment below to include it)
|
|
21
|
+
# vendor/
|
|
22
|
+
|
|
23
|
+
# Go workspace file
|
|
24
|
+
go.work
|
|
25
|
+
go.work.sum
|
|
26
|
+
|
|
27
|
+
# Project-specific build artifacts (anchored to root)
|
|
28
|
+
/webdav-server
|
|
29
|
+
/websocket-events
|
|
30
|
+
/websocket-reconnect
|
|
31
|
+
/basic
|
|
32
|
+
/go-bridge
|
|
33
|
+
|
|
34
|
+
# env file
|
|
35
|
+
.env
|
|
36
|
+
|
|
37
|
+
# Editor/IDE
|
|
38
|
+
.idea/
|
|
39
|
+
.vscode/
|
|
40
|
+
*.swp
|
|
41
|
+
*.swo
|
|
42
|
+
|
|
43
|
+
# OS
|
|
44
|
+
.DS_Store
|
|
45
|
+
Thumbs.db
|
|
46
|
+
|
|
47
|
+
# Node.js binding build artifacts
|
|
48
|
+
binding/nodejs/node_modules/
|
|
49
|
+
binding/nodejs/build/
|
|
50
|
+
binding/nodejs/lib/
|
|
51
|
+
binding/nodejs/package-lock.json
|
|
52
|
+
|
|
53
|
+
# Python binding build artifacts
|
|
54
|
+
binding/python/lib/
|
|
55
|
+
binding/python/__pycache__/
|
|
56
|
+
**/__pycache__/
|
|
57
|
+
*.pyc
|
|
58
|
+
*.pyo
|
|
59
|
+
|
|
60
|
+
# Local benchmark baselines (generated on demand)
|
|
61
|
+
bench/baseline.txt
|
|
62
|
+
# Python packaging
|
|
63
|
+
dist/
|
|
64
|
+
*.egg-info
|
|
65
|
+
build/
|
|
66
|
+
|
|
67
|
+
# napcat-cli local cruft (do not commit)
|
|
68
|
+
SKILLS_FS_DEGRADED
|
|
69
|
+
debug
|
|
70
|
+
keys.log
|
|
71
|
+
|
|
72
|
+
# Local virtualenvs (their absolute symlinks break the sdist tar)
|
|
73
|
+
.smoke/
|
|
74
|
+
.test-venv/
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: napcat-cli
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Standalone CLI and daemon for NapCat QQ bot management with skills-fs integration
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: textual>=0.40
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest>=7; extra == 'dev'
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# napcat-cli
|
|
13
|
+
|
|
14
|
+
Standalone CLI and daemon for NapCat QQ bot management with skills-fs integration.
|
|
15
|
+
|
|
16
|
+
> 📝 **介绍博文:** [napcat-cli 群配置与管理速查](https://yvxi.pages.dev/blog/napcat-cli-group-config/) — 从零配置、群消息收发、Agent Wake 的完整链路。
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
napcat-cli provides a CLI for all NapCat API operations, a WebSocket daemon
|
|
21
|
+
that bridges to a skills-fs HTTP provider, and an agent wake-up mechanism for
|
|
22
|
+
integrating with Hermes or other AI agents.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
napcat send group 123456 -m "Hello"
|
|
26
|
+
napcat send private 987654 -m "Hi"
|
|
27
|
+
napcat recall 1001
|
|
28
|
+
napcat events --limit 10
|
|
29
|
+
napcat daemon start
|
|
30
|
+
napcat wake --reason NEW_MESSAGE
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Commands
|
|
36
|
+
|
|
37
|
+
| Command | Description |
|
|
38
|
+
|---------|-------------|
|
|
39
|
+
| `napcat api <endpoint>` | Raw API access (like `gh api`) |
|
|
40
|
+
| `napcat send group <id> -m "msg"` | Send group message |
|
|
41
|
+
| `napcat send private <id> -m "msg"` | Send private message |
|
|
42
|
+
| `napcat reply <id> -m "msg"` | Reply to a message |
|
|
43
|
+
| `napcat recall <msg_id>` | Recall a message |
|
|
44
|
+
| `napcat group <sub>` | Group list, members, settings |
|
|
45
|
+
| `napcat friend <sub>` | Friend list, info |
|
|
46
|
+
| `napcat file <sub>` | File upload, download, list |
|
|
47
|
+
| `napcat events` | Read events from SQLite |
|
|
48
|
+
| `napcat alerts [--clear]` | Pending alerts |
|
|
49
|
+
| `napcat status` | Bot online status |
|
|
50
|
+
| `napcat config get/set` | Configuration management |
|
|
51
|
+
| `napcat daemon start/stop/status/restart` | Watch daemon |
|
|
52
|
+
| `napcat fs tree` | Skills-fs directory tree |
|
|
53
|
+
| `napcat wake [--reason R] [--prompt P] [--transport T] [--dry-run]` | Wake the configured agent (HTTP/CLI, auto-fallback) |
|
|
54
|
+
| `napcat setup` | Interactive setup wizard |
|
|
55
|
+
| `napcat phone` | Textual phone-style TUI |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Setup
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv tool install napcat-cli
|
|
63
|
+
napcat setup # interactive — guides token, data dir, skills-fs, wake
|
|
64
|
+
napcat daemon start
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The setup wizard writes two config files:
|
|
68
|
+
|
|
69
|
+
- `<data_dir>/config.json` — API URL, token, self_id, ports, triggers
|
|
70
|
+
- `<data_dir>/daemon.json` — All fields consumed by `watch.py` including `skills_fs_*` settings
|
|
71
|
+
|
|
72
|
+
Non-interactive mode uses defaults:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
napcat setup --non-interactive # no prompts, validates token
|
|
76
|
+
napcat setup --yes # skip token validation
|
|
77
|
+
napcat setup --force # overwrite existing config
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Agent Wake
|
|
83
|
+
|
|
84
|
+
When a notable QQ event arrives, the daemon wakes an external agent (Hermes by
|
|
85
|
+
default) carrying a **contextual prompt** so it can read the inbox and reply.
|
|
86
|
+
The wake mechanism is **generic and pluggable** — Hermes is just the default
|
|
87
|
+
preset; any HTTP endpoint or shell command works.
|
|
88
|
+
|
|
89
|
+
### Two transports, auto-fallback
|
|
90
|
+
|
|
91
|
+
| Transport | When it's used | Needs |
|
|
92
|
+
|-----------|----------------|-------|
|
|
93
|
+
| **CLI one-shot** (default) | Always available | `hermes` on PATH |
|
|
94
|
+
| **HTTP API server** | Opt-in (best latency, idempotent, in-session) | `wake_http_url` + `wake_http_key` |
|
|
95
|
+
|
|
96
|
+
`wake_primary=auto` tries HTTP first (if configured + reachable), else falls back
|
|
97
|
+
to the CLI one-shot. The Hermes CLI backend runs
|
|
98
|
+
`hermes --continue <session> -z "<prompt>" --yolo --pass-session-id`; the HTTP
|
|
99
|
+
backend POSTs to `POST /api/sessions/{id}/chat` (verified per the Hermes API
|
|
100
|
+
docs), with `Authorization: Bearer <key>` and an `Idempotency-Key` header.
|
|
101
|
+
|
|
102
|
+
### Event routing
|
|
103
|
+
|
|
104
|
+
| Trigger | Behavior |
|
|
105
|
+
|---------|----------|
|
|
106
|
+
| `AT_ME`, `REPLY_TO_ME` | Near-immediate wake (cooldown bypassed), with who/where/text in the prompt |
|
|
107
|
+
| `GROUP_TRIGGER`, `PRIVATE_TRIGGER` | Debounced wake |
|
|
108
|
+
| `NEW_MESSAGE` (not @) | Tracked, not woken; if unread longer than `wake_new_message_idle_seconds` → a `NEW_MESSAGE_BACKLOG` wake |
|
|
109
|
+
| `NEW_FRIEND`, `NEW_REQUEST`, `BOT_BANNED`, `NEW_POKE`, `GROUP_ADMIN_CHANGE`, `NEW_GROUP_MEMBER`, `BOT_OFFLINE`, … | Debounced + cooldown-bounded wake so the agent perceives them within a reasonable window |
|
|
110
|
+
|
|
111
|
+
Debounce (`wake_debounce_seconds`, default 3) coalesces a burst into one wake;
|
|
112
|
+
cooldown (`wake_cooldown_seconds`, default 30) suppresses repeats. Every wake is
|
|
113
|
+
logged to `daemon.log` as `[WAKE] trigger / queued / deliver / reply` lines
|
|
114
|
+
(including transport, elapsed time, and the agent's reply), and `daemon.log` is
|
|
115
|
+
size-rotated (2 MB × 5) so it can't fill the disk.
|
|
116
|
+
|
|
117
|
+
### Configure
|
|
118
|
+
|
|
119
|
+
The easiest path is the wizard:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
napcat setup # choose Hermes preset; CLI one-shot by default, HTTP opt-in
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Or set keys directly:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
napcat config set wake_enabled true
|
|
129
|
+
napcat config set wake_preset hermes # hermes | custom | none
|
|
130
|
+
napcat config set wake_session napcat-qq
|
|
131
|
+
napcat config set wake_primary auto # auto | http | cli
|
|
132
|
+
# HTTP (optional). Key also readable from NAPCAT_WAKE_HTTP_KEY / HERMES_API_KEY:
|
|
133
|
+
napcat config set wake_http_url http://127.0.0.1:8642
|
|
134
|
+
napcat config set wake_http_key <API_SERVER_KEY>
|
|
135
|
+
napcat config set wake_new_message_idle_seconds 600
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
To enable the Hermes HTTP API server (appends to `~/.hermes/.env` and restarts
|
|
139
|
+
the `hermes-gateway.service` systemd unit), answer "y" during `napcat setup`, or
|
|
140
|
+
set `API_SERVER_ENABLED=true` + `API_SERVER_KEY` in `~/.hermes/.env` yourself and
|
|
141
|
+
`sudo systemctl restart hermes-gateway.service`.
|
|
142
|
+
|
|
143
|
+
### Manual / debug
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
napcat wake # reason: manual, contextual default prompt
|
|
147
|
+
napcat wake --reason AT_ME --prompt "hello"
|
|
148
|
+
napcat wake --transport cli # force a transport for this wake
|
|
149
|
+
napcat wake --dry-run # render the HTTP request + CLI command without executing
|
|
150
|
+
napcat wake test # per-transport configured + reachable probe
|
|
151
|
+
napcat wake sessions # list Hermes sessions (HTTP backend)
|
|
152
|
+
grep '\[WAKE\]' ~/.napcat-data/daemon.log # see when/why/how wakes fired
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The agent replies via `napcat send` / `napcat reply` (or the skills-fs write
|
|
156
|
+
path) — see `napcat_cli/data/SKILL.md`. Legacy `wake_command` shell strings still
|
|
157
|
+
run as a last-resort escape hatch when no backend is configured.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Environment Variables
|
|
162
|
+
|
|
163
|
+
| Variable | Default | Description |
|
|
164
|
+
|----------|---------|-------------|
|
|
165
|
+
| `NAPCAT_API_URL` | `http://127.0.0.1:18801` | NapCat HTTP endpoint |
|
|
166
|
+
| `NAPCAT_TOKEN` | — | API auth token |
|
|
167
|
+
| `NAPCAT_DATA_DIR` | `~/.napcat-data` | Data directory |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## skills-fs Integration
|
|
172
|
+
|
|
173
|
+
The daemon runs an HTTP provider server (port 18820/18821) that skills-fs calls
|
|
174
|
+
to read/write NapCat API endpoints through the virtual filesystem.
|
|
175
|
+
|
|
176
|
+
When `skills_fs_enabled` is true in `daemon.json`, the daemon spawns skills-fs
|
|
177
|
+
automatically with the configured mountpoint and config file.
|
|
178
|
+
|
|
179
|
+
Manual start:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
skills-fs fuse --config ~/.napcat-data/skills-fs.json \
|
|
183
|
+
--mountpoint ~/.napcat-data/skills/napcat-cli --allow-other
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Development
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
napcat-cli/
|
|
192
|
+
├── napcat_cli/ # Installable package
|
|
193
|
+
│ ├── cli.py # CLI entry point
|
|
194
|
+
│ ├── wake.py # Wake command-template renderer
|
|
195
|
+
│ ├── wake_backend.py # Generic HTTP/CLI wake transports + Waker (auto-fallback)
|
|
196
|
+
│ ├── wake_presets.py # Hermes/custom/none presets -> Waker
|
|
197
|
+
│ ├── wake_orchestrator.py # Debounce, cooldown, backlog sweep, contextual prompts
|
|
198
|
+
│ ├── setup_wizard.py # Setup wizard
|
|
199
|
+
│ ├── daemon/ # Watch daemon, schemas
|
|
200
|
+
│ ├── lib/ # API, config, events
|
|
201
|
+
│ ├── tui/ # Textual TUI
|
|
202
|
+
│ └── data/ # SKILL.md, persona.md
|
|
203
|
+
├── pyproject.toml
|
|
204
|
+
├── tests/
|
|
205
|
+
├── skills-fs/ # Go submodule
|
|
206
|
+
└── tools/ # Dev utilities
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
python -m pytest tests/ -v
|
|
211
|
+
python -m build --wheel
|
|
212
|
+
uv build && uv publish
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# napcat-cli
|
|
2
|
+
|
|
3
|
+
Standalone CLI and daemon for NapCat QQ bot management with skills-fs integration.
|
|
4
|
+
|
|
5
|
+
> 📝 **介绍博文:** [napcat-cli 群配置与管理速查](https://yvxi.pages.dev/blog/napcat-cli-group-config/) — 从零配置、群消息收发、Agent Wake 的完整链路。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
napcat-cli provides a CLI for all NapCat API operations, a WebSocket daemon
|
|
10
|
+
that bridges to a skills-fs HTTP provider, and an agent wake-up mechanism for
|
|
11
|
+
integrating with Hermes or other AI agents.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
napcat send group 123456 -m "Hello"
|
|
15
|
+
napcat send private 987654 -m "Hi"
|
|
16
|
+
napcat recall 1001
|
|
17
|
+
napcat events --limit 10
|
|
18
|
+
napcat daemon start
|
|
19
|
+
napcat wake --reason NEW_MESSAGE
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
| Command | Description |
|
|
27
|
+
|---------|-------------|
|
|
28
|
+
| `napcat api <endpoint>` | Raw API access (like `gh api`) |
|
|
29
|
+
| `napcat send group <id> -m "msg"` | Send group message |
|
|
30
|
+
| `napcat send private <id> -m "msg"` | Send private message |
|
|
31
|
+
| `napcat reply <id> -m "msg"` | Reply to a message |
|
|
32
|
+
| `napcat recall <msg_id>` | Recall a message |
|
|
33
|
+
| `napcat group <sub>` | Group list, members, settings |
|
|
34
|
+
| `napcat friend <sub>` | Friend list, info |
|
|
35
|
+
| `napcat file <sub>` | File upload, download, list |
|
|
36
|
+
| `napcat events` | Read events from SQLite |
|
|
37
|
+
| `napcat alerts [--clear]` | Pending alerts |
|
|
38
|
+
| `napcat status` | Bot online status |
|
|
39
|
+
| `napcat config get/set` | Configuration management |
|
|
40
|
+
| `napcat daemon start/stop/status/restart` | Watch daemon |
|
|
41
|
+
| `napcat fs tree` | Skills-fs directory tree |
|
|
42
|
+
| `napcat wake [--reason R] [--prompt P] [--transport T] [--dry-run]` | Wake the configured agent (HTTP/CLI, auto-fallback) |
|
|
43
|
+
| `napcat setup` | Interactive setup wizard |
|
|
44
|
+
| `napcat phone` | Textual phone-style TUI |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Setup
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uv tool install napcat-cli
|
|
52
|
+
napcat setup # interactive — guides token, data dir, skills-fs, wake
|
|
53
|
+
napcat daemon start
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The setup wizard writes two config files:
|
|
57
|
+
|
|
58
|
+
- `<data_dir>/config.json` — API URL, token, self_id, ports, triggers
|
|
59
|
+
- `<data_dir>/daemon.json` — All fields consumed by `watch.py` including `skills_fs_*` settings
|
|
60
|
+
|
|
61
|
+
Non-interactive mode uses defaults:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
napcat setup --non-interactive # no prompts, validates token
|
|
65
|
+
napcat setup --yes # skip token validation
|
|
66
|
+
napcat setup --force # overwrite existing config
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Agent Wake
|
|
72
|
+
|
|
73
|
+
When a notable QQ event arrives, the daemon wakes an external agent (Hermes by
|
|
74
|
+
default) carrying a **contextual prompt** so it can read the inbox and reply.
|
|
75
|
+
The wake mechanism is **generic and pluggable** — Hermes is just the default
|
|
76
|
+
preset; any HTTP endpoint or shell command works.
|
|
77
|
+
|
|
78
|
+
### Two transports, auto-fallback
|
|
79
|
+
|
|
80
|
+
| Transport | When it's used | Needs |
|
|
81
|
+
|-----------|----------------|-------|
|
|
82
|
+
| **CLI one-shot** (default) | Always available | `hermes` on PATH |
|
|
83
|
+
| **HTTP API server** | Opt-in (best latency, idempotent, in-session) | `wake_http_url` + `wake_http_key` |
|
|
84
|
+
|
|
85
|
+
`wake_primary=auto` tries HTTP first (if configured + reachable), else falls back
|
|
86
|
+
to the CLI one-shot. The Hermes CLI backend runs
|
|
87
|
+
`hermes --continue <session> -z "<prompt>" --yolo --pass-session-id`; the HTTP
|
|
88
|
+
backend POSTs to `POST /api/sessions/{id}/chat` (verified per the Hermes API
|
|
89
|
+
docs), with `Authorization: Bearer <key>` and an `Idempotency-Key` header.
|
|
90
|
+
|
|
91
|
+
### Event routing
|
|
92
|
+
|
|
93
|
+
| Trigger | Behavior |
|
|
94
|
+
|---------|----------|
|
|
95
|
+
| `AT_ME`, `REPLY_TO_ME` | Near-immediate wake (cooldown bypassed), with who/where/text in the prompt |
|
|
96
|
+
| `GROUP_TRIGGER`, `PRIVATE_TRIGGER` | Debounced wake |
|
|
97
|
+
| `NEW_MESSAGE` (not @) | Tracked, not woken; if unread longer than `wake_new_message_idle_seconds` → a `NEW_MESSAGE_BACKLOG` wake |
|
|
98
|
+
| `NEW_FRIEND`, `NEW_REQUEST`, `BOT_BANNED`, `NEW_POKE`, `GROUP_ADMIN_CHANGE`, `NEW_GROUP_MEMBER`, `BOT_OFFLINE`, … | Debounced + cooldown-bounded wake so the agent perceives them within a reasonable window |
|
|
99
|
+
|
|
100
|
+
Debounce (`wake_debounce_seconds`, default 3) coalesces a burst into one wake;
|
|
101
|
+
cooldown (`wake_cooldown_seconds`, default 30) suppresses repeats. Every wake is
|
|
102
|
+
logged to `daemon.log` as `[WAKE] trigger / queued / deliver / reply` lines
|
|
103
|
+
(including transport, elapsed time, and the agent's reply), and `daemon.log` is
|
|
104
|
+
size-rotated (2 MB × 5) so it can't fill the disk.
|
|
105
|
+
|
|
106
|
+
### Configure
|
|
107
|
+
|
|
108
|
+
The easiest path is the wizard:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
napcat setup # choose Hermes preset; CLI one-shot by default, HTTP opt-in
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Or set keys directly:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
napcat config set wake_enabled true
|
|
118
|
+
napcat config set wake_preset hermes # hermes | custom | none
|
|
119
|
+
napcat config set wake_session napcat-qq
|
|
120
|
+
napcat config set wake_primary auto # auto | http | cli
|
|
121
|
+
# HTTP (optional). Key also readable from NAPCAT_WAKE_HTTP_KEY / HERMES_API_KEY:
|
|
122
|
+
napcat config set wake_http_url http://127.0.0.1:8642
|
|
123
|
+
napcat config set wake_http_key <API_SERVER_KEY>
|
|
124
|
+
napcat config set wake_new_message_idle_seconds 600
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
To enable the Hermes HTTP API server (appends to `~/.hermes/.env` and restarts
|
|
128
|
+
the `hermes-gateway.service` systemd unit), answer "y" during `napcat setup`, or
|
|
129
|
+
set `API_SERVER_ENABLED=true` + `API_SERVER_KEY` in `~/.hermes/.env` yourself and
|
|
130
|
+
`sudo systemctl restart hermes-gateway.service`.
|
|
131
|
+
|
|
132
|
+
### Manual / debug
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
napcat wake # reason: manual, contextual default prompt
|
|
136
|
+
napcat wake --reason AT_ME --prompt "hello"
|
|
137
|
+
napcat wake --transport cli # force a transport for this wake
|
|
138
|
+
napcat wake --dry-run # render the HTTP request + CLI command without executing
|
|
139
|
+
napcat wake test # per-transport configured + reachable probe
|
|
140
|
+
napcat wake sessions # list Hermes sessions (HTTP backend)
|
|
141
|
+
grep '\[WAKE\]' ~/.napcat-data/daemon.log # see when/why/how wakes fired
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The agent replies via `napcat send` / `napcat reply` (or the skills-fs write
|
|
145
|
+
path) — see `napcat_cli/data/SKILL.md`. Legacy `wake_command` shell strings still
|
|
146
|
+
run as a last-resort escape hatch when no backend is configured.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Environment Variables
|
|
151
|
+
|
|
152
|
+
| Variable | Default | Description |
|
|
153
|
+
|----------|---------|-------------|
|
|
154
|
+
| `NAPCAT_API_URL` | `http://127.0.0.1:18801` | NapCat HTTP endpoint |
|
|
155
|
+
| `NAPCAT_TOKEN` | — | API auth token |
|
|
156
|
+
| `NAPCAT_DATA_DIR` | `~/.napcat-data` | Data directory |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## skills-fs Integration
|
|
161
|
+
|
|
162
|
+
The daemon runs an HTTP provider server (port 18820/18821) that skills-fs calls
|
|
163
|
+
to read/write NapCat API endpoints through the virtual filesystem.
|
|
164
|
+
|
|
165
|
+
When `skills_fs_enabled` is true in `daemon.json`, the daemon spawns skills-fs
|
|
166
|
+
automatically with the configured mountpoint and config file.
|
|
167
|
+
|
|
168
|
+
Manual start:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
skills-fs fuse --config ~/.napcat-data/skills-fs.json \
|
|
172
|
+
--mountpoint ~/.napcat-data/skills/napcat-cli --allow-other
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
napcat-cli/
|
|
181
|
+
├── napcat_cli/ # Installable package
|
|
182
|
+
│ ├── cli.py # CLI entry point
|
|
183
|
+
│ ├── wake.py # Wake command-template renderer
|
|
184
|
+
│ ├── wake_backend.py # Generic HTTP/CLI wake transports + Waker (auto-fallback)
|
|
185
|
+
│ ├── wake_presets.py # Hermes/custom/none presets -> Waker
|
|
186
|
+
│ ├── wake_orchestrator.py # Debounce, cooldown, backlog sweep, contextual prompts
|
|
187
|
+
│ ├── setup_wizard.py # Setup wizard
|
|
188
|
+
│ ├── daemon/ # Watch daemon, schemas
|
|
189
|
+
│ ├── lib/ # API, config, events
|
|
190
|
+
│ ├── tui/ # Textual TUI
|
|
191
|
+
│ └── data/ # SKILL.md, persona.md
|
|
192
|
+
├── pyproject.toml
|
|
193
|
+
├── tests/
|
|
194
|
+
├── skills-fs/ # Go submodule
|
|
195
|
+
└── tools/ # Dev utilities
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
python -m pytest tests/ -v
|
|
200
|
+
python -m build --wheel
|
|
201
|
+
uv build && uv publish
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Agent Wake — Hermes (and other agents)
|
|
2
|
+
|
|
3
|
+
napcat-cli wakes an external agent when notable QQ events arrive, carrying a
|
|
4
|
+
contextual prompt. **Hermes is the default preset, not a hard dependency** — the
|
|
5
|
+
wake layer is generic (HTTP or shell), so any agent works.
|
|
6
|
+
|
|
7
|
+
## How a wake flows
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
QQ event → EventProcessor._wake(reason, event)
|
|
11
|
+
→ WakeOrchestrator.submit() [debounce + cooldown + backlog tracking]
|
|
12
|
+
→ Waker.wake(prompt) [HTTP first if configured, else CLI]
|
|
13
|
+
→ agent turn runs in session `wake_session` (e.g. napcat-qq)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Each step is logged to `daemon.log` with a `[WAKE]` prefix:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
[2026-07-22 00:12:03] [WAKE] trigger reason=AT_ME who=Alice(123) where=group456 text='在吗'
|
|
20
|
+
[2026-07-22 00:12:03] [WAKE] queued reason=AT_ME pending=1 debounce=1.0s primary=auto
|
|
21
|
+
[2026-07-22 00:12:05] [WAKE] deliver reason=AT_ME transport=cli ok=True elapsed=2.1s :: exit=0
|
|
22
|
+
[2026-07-22 00:12:05] [WAKE] reply reason=AT_ME transport=cli: 在的,怎么了?
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`daemon.log` is size-rotated (2 MB × 5) so it can't fill the disk.
|
|
26
|
+
|
|
27
|
+
## Transports
|
|
28
|
+
|
|
29
|
+
| Transport | Hermes target | Needs | Notes |
|
|
30
|
+
|-----------|---------------|-------|-------|
|
|
31
|
+
| `http` | `POST /api/sessions/{id}/chat` | `wake_http_url` + `wake_http_key` | Best latency, idempotent, injects into a live session; requires the API server enabled |
|
|
32
|
+
| `cli` | `hermes --continue <session> -z "<prompt>" --yolo --pass-session-id` | `hermes` on PATH | Zero infrastructure; spawns a one-shot process per wake |
|
|
33
|
+
|
|
34
|
+
`wake_primary=auto` (default) tries HTTP first when configured + reachable,
|
|
35
|
+
otherwise falls back to CLI. Force one with `napcat wake --transport http|cli`.
|
|
36
|
+
|
|
37
|
+
## Enable the Hermes HTTP API server (opt-in)
|
|
38
|
+
|
|
39
|
+
The API server is off by default. To use the HTTP transport:
|
|
40
|
+
|
|
41
|
+
1. Append to `~/.hermes/.env` (append-only — don't rewrite):
|
|
42
|
+
```dotenv
|
|
43
|
+
API_SERVER_ENABLED=true
|
|
44
|
+
API_SERVER_KEY=<random 64-hex>
|
|
45
|
+
```
|
|
46
|
+
2. Restart the gateway (systemd, passwordless sudo):
|
|
47
|
+
```bash
|
|
48
|
+
sudo systemctl restart hermes-gateway.service
|
|
49
|
+
```
|
|
50
|
+
This briefly interrupts the messaging platforms the gateway serves.
|
|
51
|
+
3. Configure napcat-cli:
|
|
52
|
+
```bash
|
|
53
|
+
napcat config set wake_http_url http://127.0.0.1:8642
|
|
54
|
+
napcat config set wake_http_key <same API_SERVER_KEY>
|
|
55
|
+
# optional: pin a specific session id instead of resolving by name
|
|
56
|
+
napcat config set wake_http_session_id <session-id>
|
|
57
|
+
```
|
|
58
|
+
`napcat setup` does all three interactively when you answer "y" to the
|
|
59
|
+
HTTP-enable prompt.
|
|
60
|
+
|
|
61
|
+
### Verified request shape
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
curl -X POST http://127.0.0.1:8642/api/sessions/$SESSION_ID/chat \
|
|
65
|
+
-H "Authorization: Bearer $API_SERVER_KEY" \
|
|
66
|
+
-H "Idempotency-Key: napcat-AT_ME-1700000000" \
|
|
67
|
+
-H "Content-Type: application/json" \
|
|
68
|
+
-d '{"input":"你在群里被 @ 了…请查看并回复。"}'
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If `wake_http_session_id` is unset, the backend resolves it by name via
|
|
72
|
+
`GET /api/sessions`. Docs: <https://hermes-agent.nousresearch.com/docs/user-guide/features/api-server>
|
|
73
|
+
|
|
74
|
+
## Event routing & timing
|
|
75
|
+
|
|
76
|
+
| Reason | Wake? | Timing |
|
|
77
|
+
|--------|-------|--------|
|
|
78
|
+
| `AT_ME`, `REPLY_TO_ME` | yes | near-immediate (debounce ≤1 s), **cooldown bypassed** |
|
|
79
|
+
| `GROUP_TRIGGER`, `PRIVATE_TRIGGER` | yes | debounced |
|
|
80
|
+
| `NEW_MESSAGE` (not @) | tracked only | a `NEW_MESSAGE_BACKLOG` wake fires if unread > `wake_new_message_idle_seconds` (default 600) |
|
|
81
|
+
| `NEW_FRIEND`, `NEW_REQUEST`, `BOT_BANNED`, `NEW_POKE`, `GROUP_ADMIN_CHANGE`, `NEW_GROUP_MEMBER`, `MY_MESSAGE_RECALLED`, `BOT_KICKED_FROM_GROUP`, `GROUP_DISBANDED`, `BOT_OFFLINE`, `HEALTH_CHECK_OFFLINE` | yes | debounced + cooldown-bounded |
|
|
82
|
+
|
|
83
|
+
Tuning keys: `wake_debounce_seconds` (default 3), `wake_cooldown_seconds`
|
|
84
|
+
(default 30), `wake_new_message_idle_seconds` (default 600).
|
|
85
|
+
|
|
86
|
+
## Troubleshooting
|
|
87
|
+
|
|
88
|
+
- **`napcat wake test`** — reports per-transport configured/reachable and whether
|
|
89
|
+
`hermes` is on PATH.
|
|
90
|
+
- **No wake fires** — check `wake_enabled` is true and `wake_preset` ≠ `none`;
|
|
91
|
+
grep `[WAKE]` in `daemon.log`. `disabled, skip` means `wake_enabled=false`.
|
|
92
|
+
- **HTTP 401 / unreachable** — `auto` falls back to CLI automatically; to use
|
|
93
|
+
HTTP, confirm `API_SERVER_ENABLED=true` and the gateway was restarted.
|
|
94
|
+
- **Legacy `wake_command`** still runs as a last-resort escape hatch when no
|
|
95
|
+
backend is configured (back-compat for `echo … >> .agent-wake` configs).
|