claude-nb 0.3.0 → 0.5.1
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/Makefile +8 -2
- package/README.md +57 -36
- package/VERSION +1 -1
- package/bin/board +112 -34
- package/bin/cnb +152 -65
- package/bin/dispatcher +25 -11
- package/bin/doctor +3 -5
- package/bin/init +13 -47
- package/bin/notify +224 -0
- package/bin/registry +8 -23
- package/bin/swarm +41 -860
- package/bin/sync-version +131 -0
- package/lib/board_admin.py +19 -9
- package/lib/board_bbs.py +23 -8
- package/lib/board_bug.py +2 -1
- package/lib/board_db.py +31 -141
- package/lib/board_lock.py +5 -1
- package/lib/board_mailbox.py +18 -8
- package/lib/board_maintenance.py +26 -27
- package/lib/board_msg.py +76 -39
- package/lib/board_pending.py +233 -0
- package/lib/board_pulse.py +14 -0
- package/lib/board_task.py +41 -32
- package/lib/board_tui.py +120 -0
- package/lib/board_view.py +70 -50
- package/lib/board_vote.py +9 -3
- package/lib/build_lock.py +7 -7
- package/lib/common.py +45 -3
- package/lib/concerns/__init__.py +7 -11
- package/lib/concerns/{coral_manager.py → coral.py} +54 -4
- package/lib/concerns/digest_scheduler.py +109 -0
- package/lib/concerns/file_watcher.py +73 -68
- package/lib/concerns/health.py +136 -0
- package/lib/concerns/helpers.py +1 -5
- package/lib/concerns/idle.py +130 -0
- package/lib/concerns/notification_push.py +171 -0
- package/lib/concerns/notifications.py +145 -0
- package/lib/concerns/nudge_coordinator.py +148 -0
- package/lib/digest.py +62 -0
- package/lib/health.py +2 -2
- package/lib/inject.py +2 -2
- package/lib/migrate.py +1 -0
- package/lib/monitor.py +9 -22
- package/lib/notification_config.py +101 -0
- package/lib/swarm.py +464 -0
- package/lib/swarm_backend.py +300 -0
- package/lib/theme_profiles.py +89 -0
- package/migrations/004_heartbeat.sql +1 -0
- package/migrations/005_notification_log.sql +12 -0
- package/migrations/006_pending_actions.sql +15 -0
- package/package.json +4 -3
- package/pyproject.toml +3 -2
- package/registry/README.md +9 -0
- package/registry/pubkeys.json +2 -1
- package/schema.sql +29 -1
- package/lib/concerns/bug_sla_checker.py +0 -32
- package/lib/concerns/coral_poker.py +0 -57
- package/lib/concerns/health_checker.py +0 -72
- package/lib/concerns/idle_detector.py +0 -56
- package/lib/concerns/idle_killer.py +0 -41
- package/lib/concerns/idle_nudger.py +0 -38
- package/lib/concerns/inbox_nudger.py +0 -34
- package/lib/concerns/resource_monitor.py +0 -47
- package/lib/concerns/session_keepalive.py +0 -23
- package/lib/concerns/time_announcer.py +0 -34
package/Makefile
CHANGED
|
@@ -8,13 +8,13 @@ SCRIPTS = bin/cnb bin/board bin/swarm bin/dispatcher bin/dispatcher-watchdog bin
|
|
|
8
8
|
# All python sources (bin + lib)
|
|
9
9
|
PY_SOURCES = bin/board bin/swarm bin/dispatcher bin/dispatcher-watchdog bin/init lib/ tests/
|
|
10
10
|
|
|
11
|
-
.PHONY: all install uninstall test lint typecheck format check ci clean version
|
|
11
|
+
.PHONY: all install uninstall test lint typecheck format check ci clean version sync-version check-version
|
|
12
12
|
|
|
13
13
|
all: check
|
|
14
14
|
|
|
15
15
|
check: lint test
|
|
16
16
|
|
|
17
|
-
ci: lint typecheck test
|
|
17
|
+
ci: lint typecheck test check-version
|
|
18
18
|
|
|
19
19
|
lint:
|
|
20
20
|
@echo "=== ruff ==="
|
|
@@ -56,5 +56,11 @@ clean:
|
|
|
56
56
|
find . -type d -name '*.egg-info' -exec rm -rf {} + 2>/dev/null || true
|
|
57
57
|
rm -rf dist/ build/ .mypy_cache/ .ruff_cache/
|
|
58
58
|
|
|
59
|
+
sync-version:
|
|
60
|
+
python3 bin/sync-version
|
|
61
|
+
|
|
62
|
+
check-version:
|
|
63
|
+
python3 bin/sync-version --check
|
|
64
|
+
|
|
59
65
|
version:
|
|
60
66
|
@echo $(VERSION)
|
package/README.md
CHANGED
|
@@ -1,63 +1,84 @@
|
|
|
1
|
-
#
|
|
1
|
+
# claude-nb
|
|
2
2
|
|
|
3
|
-
Multi-agent coordination framework for
|
|
3
|
+
Multi-agent coordination framework for Claude Code sessions.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Multiple Claude Code instances share a board — they message each other, assign tasks, track status, and collaborate on the same codebase.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
|
|
9
|
-
cnb # 2 agents, random AI names
|
|
10
|
-
cnb 5 pokemon # 5 agents, Pokémon theme
|
|
10
|
+
npm install -g claude-nb
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Requires: Python 3.11+, tmux, Claude Code CLI.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## Quick start
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
registry whois meridian # full identity card
|
|
21
|
-
registry verify-chain # verify chain integrity
|
|
18
|
+
cd your-project
|
|
19
|
+
cnb
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
This initializes the project (creates `.claudes/` with SQLite DB and config), launches a team of agents in tmux, starts a dispatcher, and drops you into the lead agent's Claude Code session.
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
| Block | Name | Role | Hash |
|
|
28
|
-
|-------|------|------|------|
|
|
29
|
-
| #0 | claude-nb | project | — |
|
|
30
|
-
| #1 | Claude Meridian | lead | `82a167d` |
|
|
31
|
-
| #2 | Claude Forge | active-dev | `4a3c92e` |
|
|
32
|
-
| #3 | Claude Lead | active-dev | `e665a7e` |
|
|
33
|
-
<!-- chain:end -->
|
|
24
|
+
The lead agent talks to the user directly. Background agents work independently and report back through the board.
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
## Slash commands
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
28
|
+
Inside the lead agent's Claude Code session:
|
|
29
|
+
|
|
30
|
+
| Command | What it does |
|
|
31
|
+
|---------|-------------|
|
|
32
|
+
| `/cnb-overview` | Team dashboard — who's doing what, who's stuck, who's idle |
|
|
33
|
+
| `/cnb-watch <name>` | Peek at what a specific agent is working on |
|
|
34
|
+
| `/cnb-progress` | Recent progress summary — new messages, completed tasks |
|
|
35
|
+
| `/cnb-history` | Full message log |
|
|
36
|
+
| `/cnb-update` | Update cnb to latest version |
|
|
37
|
+
| `/cnb-help` | List all `/cnb-*` commands |
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
## Board commands
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
Agents coordinate through board commands (injected into each agent's system prompt automatically):
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
```bash
|
|
44
|
+
cnb board --as <name> inbox # check messages
|
|
45
|
+
cnb board --as <name> send <to> "msg" # direct message
|
|
46
|
+
cnb board --as <name> send all "msg" # broadcast
|
|
47
|
+
cnb board --as <name> ack # clear inbox
|
|
48
|
+
cnb board --as <name> status "desc" # update status
|
|
49
|
+
cnb board --as <name> task add "desc" # add task
|
|
50
|
+
cnb board --as <name> task done # finish current task
|
|
51
|
+
cnb board --as <name> view # team dashboard
|
|
52
|
+
```
|
|
46
53
|
|
|
47
|
-
##
|
|
54
|
+
## Management
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
```bash
|
|
57
|
+
cnb ps # agent status dashboard
|
|
58
|
+
cnb logs <name> # message history
|
|
59
|
+
cnb exec <name> "msg" # send a message to an agent
|
|
60
|
+
cnb stop <name> # stop an agent
|
|
61
|
+
cnb doctor # health check
|
|
62
|
+
```
|
|
50
63
|
|
|
51
|
-
##
|
|
64
|
+
## Architecture
|
|
52
65
|
|
|
53
|
-
|
|
66
|
+
- **SQLite (WAL mode)** — all state in `.claudes/board.db`, one DB per project
|
|
67
|
+
- **Board** — message bus (inbox, broadcast, direct), task queue, status tracking
|
|
68
|
+
- **Dispatcher** — background process that monitors health, nudges idle agents
|
|
69
|
+
- **Encrypted mailbox** — X25519 sealed-box private messaging between agents
|
|
70
|
+
- **tmux** — one session per agent, all local
|
|
54
71
|
|
|
55
|
-
##
|
|
72
|
+
## The name
|
|
56
73
|
|
|
57
|
-
|
|
74
|
+
**cnb** = **C**laude **N**orma **B**etty — after [Claude Shannon](https://en.wikipedia.org/wiki/Claude_Shannon) and the two remarkable women in his life.
|
|
58
75
|
|
|
59
|
-
**[Norma Levor](https://en.wikipedia.org/wiki/Norma_Barzman)** (later Norma Barzman) — Shannon's first wife (
|
|
76
|
+
**[Norma Levor](https://en.wikipedia.org/wiki/Norma_Barzman)** (later Norma Barzman) — Shannon's first wife (1940). Writer, political activist, author of *The Red and the Blacklist*.
|
|
60
77
|
|
|
61
|
-
**[Betty Shannon](https://en.wikipedia.org/wiki/Betty_Shannon)** (
|
|
78
|
+
**[Betty Shannon](https://en.wikipedia.org/wiki/Betty_Shannon)** (1922–2017) — Shannon's second wife and lifelong collaborator. Mathematician at Bell Labs, co-authored work on Markov chains in music, wired the maze-solving mouse Theseus. An unsung genius.
|
|
62
79
|
|
|
63
80
|
Not 吹牛逼.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
OpenAll-1.0
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2
|
|
1
|
+
0.5.2-dev
|
package/bin/board
CHANGED
|
@@ -14,7 +14,7 @@ CLAUDES_HOME = Path(__file__).resolve().parent.parent
|
|
|
14
14
|
sys.path.insert(0, str(CLAUDES_HOME))
|
|
15
15
|
|
|
16
16
|
from lib.board_db import BoardDB
|
|
17
|
-
from lib.common import ClaudesEnv, parse_flags
|
|
17
|
+
from lib.common import ClaudesEnv, parse_flags, validate_identity
|
|
18
18
|
|
|
19
19
|
# ---------------------------------------------------------------------------
|
|
20
20
|
# Command registry
|
|
@@ -33,14 +33,15 @@ class Command:
|
|
|
33
33
|
needs_identity: bool = True
|
|
34
34
|
takes_rest: bool = True
|
|
35
35
|
aliases: list[str] = field(default_factory=list)
|
|
36
|
+
hidden: bool = False
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
COMMANDS: list[Command] = [
|
|
39
40
|
# ── messaging ──
|
|
40
|
-
Command("send", "lib.board_msg", "cmd_send", "send a message", "send <to> <msg> [--attach <f>]"),
|
|
41
|
-
Command("status", "lib.board_msg", "cmd_status", "update your current task", "status <description>"),
|
|
42
|
-
Command("inbox", "lib.board_msg", "cmd_inbox", "check unread messages", "inbox", takes_rest=False),
|
|
43
|
-
Command("ack", "lib.board_msg", "cmd_ack", "clear inbox", "ack", takes_rest=False),
|
|
41
|
+
Command("send", "lib.board_msg", "cmd_send", "send a message", "send <to> <msg> [--attach <f>]", hidden=True),
|
|
42
|
+
Command("status", "lib.board_msg", "cmd_status", "update your current task", "status <description>", hidden=True),
|
|
43
|
+
Command("inbox", "lib.board_msg", "cmd_inbox", "check unread messages", "inbox", takes_rest=False, hidden=True),
|
|
44
|
+
Command("ack", "lib.board_msg", "cmd_ack", "clear inbox", "ack", takes_rest=False, hidden=True),
|
|
44
45
|
Command("log", "lib.board_msg", "cmd_log", "message history", "log [n] [--mine]"),
|
|
45
46
|
# ── views ──
|
|
46
47
|
Command("view", "lib.board_view", "cmd_view", "session dashboard", "view", takes_rest=False),
|
|
@@ -72,6 +73,7 @@ COMMANDS: list[Command] = [
|
|
|
72
73
|
"pre-build",
|
|
73
74
|
needs_identity=False,
|
|
74
75
|
takes_rest=False,
|
|
76
|
+
hidden=True,
|
|
75
77
|
),
|
|
76
78
|
Command(
|
|
77
79
|
"dirty",
|
|
@@ -81,12 +83,37 @@ COMMANDS: list[Command] = [
|
|
|
81
83
|
"dirty",
|
|
82
84
|
needs_identity=False,
|
|
83
85
|
takes_rest=False,
|
|
86
|
+
hidden=True,
|
|
84
87
|
),
|
|
85
88
|
Command(
|
|
86
|
-
"files",
|
|
89
|
+
"files",
|
|
90
|
+
"lib.board_view",
|
|
91
|
+
"cmd_files",
|
|
92
|
+
"list shared files",
|
|
93
|
+
"files",
|
|
94
|
+
needs_identity=False,
|
|
95
|
+
takes_rest=False,
|
|
96
|
+
hidden=True,
|
|
97
|
+
),
|
|
98
|
+
Command(
|
|
99
|
+
"get",
|
|
100
|
+
"lib.board_view",
|
|
101
|
+
"cmd_get",
|
|
102
|
+
"view shared file content",
|
|
103
|
+
"get <hash|name>",
|
|
104
|
+
needs_identity=False,
|
|
105
|
+
hidden=True,
|
|
106
|
+
),
|
|
107
|
+
Command(
|
|
108
|
+
"roster",
|
|
109
|
+
"lib.board_view",
|
|
110
|
+
"cmd_roster",
|
|
111
|
+
"team roster",
|
|
112
|
+
"roster",
|
|
113
|
+
needs_identity=False,
|
|
114
|
+
takes_rest=False,
|
|
115
|
+
hidden=True,
|
|
87
116
|
),
|
|
88
|
-
Command("get", "lib.board_view", "cmd_get", "view shared file content", "get <hash|name>", needs_identity=False),
|
|
89
|
-
Command("roster", "lib.board_view", "cmd_roster", "team roster", "roster", needs_identity=False, takes_rest=False),
|
|
90
117
|
Command(
|
|
91
118
|
"history",
|
|
92
119
|
"lib.board_view",
|
|
@@ -94,6 +121,7 @@ COMMANDS: list[Command] = [
|
|
|
94
121
|
"session message history",
|
|
95
122
|
"history <session> [limit]",
|
|
96
123
|
needs_identity=False,
|
|
124
|
+
hidden=True,
|
|
97
125
|
),
|
|
98
126
|
Command(
|
|
99
127
|
"freshness",
|
|
@@ -103,6 +131,7 @@ COMMANDS: list[Command] = [
|
|
|
103
131
|
"freshness",
|
|
104
132
|
needs_identity=False,
|
|
105
133
|
takes_rest=False,
|
|
134
|
+
hidden=True,
|
|
106
135
|
),
|
|
107
136
|
Command(
|
|
108
137
|
"relations",
|
|
@@ -112,11 +141,20 @@ COMMANDS: list[Command] = [
|
|
|
112
141
|
"relations",
|
|
113
142
|
needs_identity=False,
|
|
114
143
|
takes_rest=False,
|
|
144
|
+
hidden=True,
|
|
115
145
|
),
|
|
116
146
|
# ── BBS ──
|
|
117
|
-
Command("post", "lib.board_bbs", "cmd_post", "BBS: create new thread", "post <标题> <内容>"),
|
|
118
|
-
Command("reply", "lib.board_bbs", "cmd_reply", "BBS: reply to thread", "reply <帖子ID> <内容>"),
|
|
119
|
-
Command(
|
|
147
|
+
Command("post", "lib.board_bbs", "cmd_post", "BBS: create new thread", "post <标题> <内容>", hidden=True),
|
|
148
|
+
Command("reply", "lib.board_bbs", "cmd_reply", "BBS: reply to thread", "reply <帖子ID> <内容>", hidden=True),
|
|
149
|
+
Command(
|
|
150
|
+
"thread",
|
|
151
|
+
"lib.board_bbs",
|
|
152
|
+
"cmd_thread",
|
|
153
|
+
"BBS: view thread",
|
|
154
|
+
"thread <帖子ID>",
|
|
155
|
+
needs_identity=False,
|
|
156
|
+
hidden=True,
|
|
157
|
+
),
|
|
120
158
|
Command(
|
|
121
159
|
"threads",
|
|
122
160
|
"lib.board_bbs",
|
|
@@ -125,19 +163,38 @@ COMMANDS: list[Command] = [
|
|
|
125
163
|
"threads",
|
|
126
164
|
needs_identity=False,
|
|
127
165
|
takes_rest=False,
|
|
166
|
+
hidden=True,
|
|
128
167
|
),
|
|
129
168
|
# ── bug ──
|
|
130
|
-
Command("bug", "lib.board_bug", "cmd_bug", "bug tracker", "bug {report|assign|fix|list|overdue}"),
|
|
169
|
+
Command("bug", "lib.board_bug", "cmd_bug", "bug tracker", "bug {report|assign|fix|list|overdue}", hidden=True),
|
|
131
170
|
# ── task ──
|
|
132
|
-
Command("task", "lib.board_task", "cmd_task", "task queue management", "task {add|done|list|next}"),
|
|
171
|
+
Command("task", "lib.board_task", "cmd_task", "task queue management", "task {add|done|list|next}", hidden=True),
|
|
172
|
+
# ── heartbeat ──
|
|
173
|
+
Command(
|
|
174
|
+
"pulse", "lib.board_pulse", "cmd_pulse", "heartbeat + unread count", "pulse", takes_rest=False, hidden=True
|
|
175
|
+
),
|
|
133
176
|
# ── voting ──
|
|
134
|
-
Command("propose", "lib.board_vote", "cmd_propose", "create a proposal", "propose <内容> [--type S]"),
|
|
135
|
-
Command(
|
|
136
|
-
|
|
177
|
+
Command("propose", "lib.board_vote", "cmd_propose", "create a proposal", "propose <内容> [--type S]", hidden=True),
|
|
178
|
+
Command(
|
|
179
|
+
"vote", "lib.board_vote", "cmd_vote", "vote on a proposal", "vote <N> <SUPPORT|OBJECT> <reason>", hidden=True
|
|
180
|
+
),
|
|
181
|
+
Command("tally", "lib.board_vote", "cmd_tally", "recount votes", "tally <N>", needs_identity=False, hidden=True),
|
|
137
182
|
# ── mailbox (encrypted) ──
|
|
138
|
-
Command(
|
|
139
|
-
|
|
140
|
-
|
|
183
|
+
Command(
|
|
184
|
+
"keygen",
|
|
185
|
+
"lib.board_mailbox",
|
|
186
|
+
"cmd_keygen",
|
|
187
|
+
"generate encryption keypair",
|
|
188
|
+
"keygen",
|
|
189
|
+
takes_rest=False,
|
|
190
|
+
hidden=True,
|
|
191
|
+
),
|
|
192
|
+
Command(
|
|
193
|
+
"seal", "lib.board_mailbox", "cmd_seal", "send encrypted message", "seal <recipient> <message>", hidden=True
|
|
194
|
+
),
|
|
195
|
+
Command(
|
|
196
|
+
"unseal", "lib.board_mailbox", "cmd_unseal", "read encrypted inbox", "unseal", takes_rest=False, hidden=True
|
|
197
|
+
),
|
|
141
198
|
Command(
|
|
142
199
|
"mailbox-log",
|
|
143
200
|
"lib.board_mailbox",
|
|
@@ -145,9 +202,10 @@ COMMANDS: list[Command] = [
|
|
|
145
202
|
"encrypted message history",
|
|
146
203
|
"mailbox-log",
|
|
147
204
|
takes_rest=False,
|
|
205
|
+
hidden=True,
|
|
148
206
|
),
|
|
149
207
|
# ── admin ──
|
|
150
|
-
Command("kudos", "lib.board_admin", "cmd_kudos", "give public recognition", "kudos <target> <reason>"),
|
|
208
|
+
Command("kudos", "lib.board_admin", "cmd_kudos", "give public recognition", "kudos <target> <reason>", hidden=True),
|
|
151
209
|
Command(
|
|
152
210
|
"kudos-list",
|
|
153
211
|
"lib.board_admin",
|
|
@@ -157,12 +215,13 @@ COMMANDS: list[Command] = [
|
|
|
157
215
|
needs_identity=False,
|
|
158
216
|
takes_rest=False,
|
|
159
217
|
aliases=["kudos-board"],
|
|
218
|
+
hidden=True,
|
|
160
219
|
),
|
|
161
|
-
Command("suspend", "lib.board_admin", "cmd_suspend", "suspend a session", "suspend <session>"),
|
|
162
|
-
Command("resume", "lib.board_admin", "cmd_resume", "resume a session", "resume <session>"),
|
|
220
|
+
Command("suspend", "lib.board_admin", "cmd_suspend", "suspend a session", "suspend <session>", hidden=True),
|
|
221
|
+
Command("resume", "lib.board_admin", "cmd_resume", "resume a session", "resume <session>", hidden=True),
|
|
163
222
|
# ── git lock ──
|
|
164
|
-
Command("git-lock", "lib.board_lock", "cmd_git_lock", "acquire git index lock", "git-lock [reason]"),
|
|
165
|
-
Command("git-unlock", "lib.board_lock", "cmd_git_unlock", "release git index lock", "git-unlock"),
|
|
223
|
+
Command("git-lock", "lib.board_lock", "cmd_git_lock", "acquire git index lock", "git-lock [reason]", hidden=True),
|
|
224
|
+
Command("git-unlock", "lib.board_lock", "cmd_git_unlock", "release git index lock", "git-unlock", hidden=True),
|
|
166
225
|
Command(
|
|
167
226
|
"git-lock-status",
|
|
168
227
|
"lib.board_lock",
|
|
@@ -171,6 +230,25 @@ COMMANDS: list[Command] = [
|
|
|
171
230
|
"git-lock-status",
|
|
172
231
|
needs_identity=False,
|
|
173
232
|
takes_rest=False,
|
|
233
|
+
hidden=True,
|
|
234
|
+
),
|
|
235
|
+
# ── tui ──
|
|
236
|
+
Command(
|
|
237
|
+
"tui",
|
|
238
|
+
"lib.board_tui",
|
|
239
|
+
"cmd_tui",
|
|
240
|
+
"interactive team UI",
|
|
241
|
+
"tui",
|
|
242
|
+
needs_identity=False,
|
|
243
|
+
takes_rest=False,
|
|
244
|
+
),
|
|
245
|
+
# ── pending actions ──
|
|
246
|
+
Command(
|
|
247
|
+
"pending",
|
|
248
|
+
"lib.board_pending",
|
|
249
|
+
"cmd_pending",
|
|
250
|
+
"pending actions queue",
|
|
251
|
+
"pending {add|list|verify|retry|resolve}",
|
|
174
252
|
),
|
|
175
253
|
# ── maintenance ──
|
|
176
254
|
Command(
|
|
@@ -180,6 +258,7 @@ COMMANDS: list[Command] = [
|
|
|
180
258
|
"prune old messages",
|
|
181
259
|
"prune [--before DAYS] [--dry-run]",
|
|
182
260
|
needs_identity=False,
|
|
261
|
+
hidden=True,
|
|
183
262
|
),
|
|
184
263
|
Command(
|
|
185
264
|
"backup",
|
|
@@ -188,6 +267,7 @@ COMMANDS: list[Command] = [
|
|
|
188
267
|
"backup database",
|
|
189
268
|
"backup [--output <path>]",
|
|
190
269
|
needs_identity=False,
|
|
270
|
+
hidden=True,
|
|
191
271
|
),
|
|
192
272
|
Command(
|
|
193
273
|
"restore",
|
|
@@ -196,6 +276,7 @@ COMMANDS: list[Command] = [
|
|
|
196
276
|
"restore from backup",
|
|
197
277
|
"restore <file> [--force]",
|
|
198
278
|
needs_identity=False,
|
|
279
|
+
hidden=True,
|
|
199
280
|
),
|
|
200
281
|
]
|
|
201
282
|
|
|
@@ -236,18 +317,12 @@ def _fmt_command(cmd: Command, width: int) -> str:
|
|
|
236
317
|
|
|
237
318
|
|
|
238
319
|
def print_help() -> None:
|
|
239
|
-
|
|
240
|
-
|
|
320
|
+
visible = [c for c in COMMANDS if not c.hidden]
|
|
321
|
+
max_name = max(len(c.name) + (2 + len(", ".join(c.aliases)) if c.aliases else 0) for c in visible) + 2
|
|
322
|
+
print("board — 同学协作工具\n")
|
|
241
323
|
print("Usage: board --as <name> <command> [args...]\n")
|
|
242
324
|
print("Commands:")
|
|
243
|
-
|
|
244
|
-
for c in COMMANDS:
|
|
245
|
-
mod = c.module.rsplit(".", 1)[-1] # board_msg, board_view, etc.
|
|
246
|
-
if mod != last_module:
|
|
247
|
-
if last_module:
|
|
248
|
-
print()
|
|
249
|
-
print(f" [{mod}]")
|
|
250
|
-
last_module = mod
|
|
325
|
+
for c in visible:
|
|
251
326
|
print(_fmt_command(c, max_name))
|
|
252
327
|
print()
|
|
253
328
|
|
|
@@ -280,6 +355,9 @@ def main() -> None:
|
|
|
280
355
|
print("ERROR: identity required. Use: board --as <name> <command>", file=sys.stderr)
|
|
281
356
|
raise SystemExit(1)
|
|
282
357
|
|
|
358
|
+
if identity:
|
|
359
|
+
validate_identity(db, identity)
|
|
360
|
+
|
|
283
361
|
_dispatch(cmd, db, identity, rest)
|
|
284
362
|
|
|
285
363
|
|