@awiki/cli 0.0.1-beta.2

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.
Files changed (119) hide show
  1. package/.github/workflows/release.yml +44 -0
  2. package/.goreleaser.yml +44 -0
  3. package/AGENTS.md +60 -0
  4. package/CLAUDE.md +192 -0
  5. package/README.md +2 -0
  6. package/docs/architecture/awiki-command-v2.md +955 -0
  7. package/docs/architecture/awiki-skill-architecture.md +475 -0
  8. package/docs/architecture/awiki-v2-architecture.md +1063 -0
  9. package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/cli-init.md +1008 -0
  10. package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/output-format.md +407 -0
  11. package/docs/architecture//345/217/202/350/200/203/346/226/207/346/241/243/overall-init.md +741 -0
  12. package/docs/harness/review-spec.md +474 -0
  13. package/docs/installation.md +372 -0
  14. package/docs/plan/awiki-v2-implementation-plan.md +903 -0
  15. package/docs/plan/phase-0/adr-index.md +56 -0
  16. package/docs/plan/phase-0/audit-findings.md +251 -0
  17. package/docs/plan/phase-0/capability-mapping.md +108 -0
  18. package/docs/plan/phase-0/implementation-constraints.md +363 -0
  19. package/docs/publish.md +169 -0
  20. package/go.mod +29 -0
  21. package/go.sum +73 -0
  22. package/internal/anpsdk/registry.go +63 -0
  23. package/internal/authsdk/session.go +351 -0
  24. package/internal/buildinfo/buildinfo.go +34 -0
  25. package/internal/cli/app.go +136 -0
  26. package/internal/cli/app_test.go +88 -0
  27. package/internal/cli/debug.go +104 -0
  28. package/internal/cli/group.go +263 -0
  29. package/internal/cli/id.go +473 -0
  30. package/internal/cli/init.go +134 -0
  31. package/internal/cli/msg.go +228 -0
  32. package/internal/cli/page.go +267 -0
  33. package/internal/cli/root.go +499 -0
  34. package/internal/cli/runtime.go +232 -0
  35. package/internal/cli/upgrade.go +60 -0
  36. package/internal/cmdmeta/catalog.go +203 -0
  37. package/internal/cmdmeta/catalog_test.go +21 -0
  38. package/internal/config/config.go +399 -0
  39. package/internal/config/config_test.go +104 -0
  40. package/internal/config/write.go +37 -0
  41. package/internal/content/service.go +314 -0
  42. package/internal/content/service_test.go +165 -0
  43. package/internal/content/types.go +44 -0
  44. package/internal/docs/topics.go +110 -0
  45. package/internal/doctor/doctor.go +306 -0
  46. package/internal/identity/client.go +267 -0
  47. package/internal/identity/did.go +85 -0
  48. package/internal/identity/did_test.go +50 -0
  49. package/internal/identity/layout.go +206 -0
  50. package/internal/identity/legacy.go +378 -0
  51. package/internal/identity/public.go +70 -0
  52. package/internal/identity/public_test.go +73 -0
  53. package/internal/identity/readiness.go +74 -0
  54. package/internal/identity/service.go +826 -0
  55. package/internal/identity/store.go +385 -0
  56. package/internal/identity/store_test.go +180 -0
  57. package/internal/identity/types.go +204 -0
  58. package/internal/message/auth.go +167 -0
  59. package/internal/message/group_service.go +838 -0
  60. package/internal/message/group_wire.go +350 -0
  61. package/internal/message/group_wire_test.go +67 -0
  62. package/internal/message/helpers.go +61 -0
  63. package/internal/message/http_client.go +334 -0
  64. package/internal/message/proof.go +156 -0
  65. package/internal/message/proof_test.go +61 -0
  66. package/internal/message/service.go +696 -0
  67. package/internal/message/service_test.go +97 -0
  68. package/internal/message/types.go +155 -0
  69. package/internal/message/wire.go +100 -0
  70. package/internal/message/wire_test.go +49 -0
  71. package/internal/message/ws_proxy_client.go +151 -0
  72. package/internal/output/output.go +350 -0
  73. package/internal/output/output_test.go +48 -0
  74. package/internal/runtime/config.go +117 -0
  75. package/internal/runtime/config_test.go +46 -0
  76. package/internal/runtime/listener/files.go +65 -0
  77. package/internal/runtime/listener/manager.go +142 -0
  78. package/internal/runtime/listener/server.go +983 -0
  79. package/internal/runtime/listener/server_test.go +319 -0
  80. package/internal/runtime/listener/sysproc_unix.go +17 -0
  81. package/internal/runtime/listener/sysproc_windows.go +13 -0
  82. package/internal/runtime/listener/types.go +21 -0
  83. package/internal/runtime/listener/wsclient.go +299 -0
  84. package/internal/runtime/listener/wsclient_test.go +41 -0
  85. package/internal/store/dao.go +632 -0
  86. package/internal/store/dao_test.go +87 -0
  87. package/internal/store/helpers.go +197 -0
  88. package/internal/store/import.go +499 -0
  89. package/internal/store/import_test.go +103 -0
  90. package/internal/store/open.go +71 -0
  91. package/internal/store/query.go +151 -0
  92. package/internal/store/schema.go +277 -0
  93. package/internal/store/schema_test.go +56 -0
  94. package/internal/store/types.go +177 -0
  95. package/internal/update/update.go +368 -0
  96. package/package.json +17 -0
  97. package/scripts/install.js +171 -0
  98. package/scripts/release/release-prerelease.sh +86 -0
  99. package/scripts/release/tag-release.sh +66 -0
  100. package/scripts/release/withdraw-release.sh +78 -0
  101. package/scripts/run.js +69 -0
  102. package/skills/README.md +32 -0
  103. package/skills/awiki-bundle/SKILL.md +76 -0
  104. package/skills/awiki-debug/SKILL.md +80 -0
  105. package/skills/awiki-group/SKILL.md +111 -0
  106. package/skills/awiki-id/SKILL.md +123 -0
  107. package/skills/awiki-msg/SKILL.md +131 -0
  108. package/skills/awiki-page/SKILL.md +93 -0
  109. package/skills/awiki-people/SKILL.md +66 -0
  110. package/skills/awiki-runtime/SKILL.md +137 -0
  111. package/skills/awiki-shared/SKILL.md +124 -0
  112. package/skills/awiki-workflow-discovery/SKILL.md +93 -0
  113. package/skills/awiki-workflow-onboarding/SKILL.md +119 -0
  114. package/skills/manifests/skills.yaml +260 -0
  115. package/skills/templates/bundle-skill-template.md +42 -0
  116. package/skills/templates/debug-skill-template.md +44 -0
  117. package/skills/templates/domain-skill-template.md +56 -0
  118. package/skills/templates/shared-skill-template.md +46 -0
  119. package/skills/templates/workflow-skill-template.md +46 -0
@@ -0,0 +1,955 @@
1
+ 可以。下面这份我按“**最终定版**”来写:它保留了 `cli-init.md` 和 `output-format.md` 里的核心内容——统一 CLI、core/extension 分层、消息三维模型、`schema`、`--dry-run`、`--jq`、shortcut、结构化输出、skill 拆分、legacy 映射——但把实现语言、工程结构和发布方式正式切换成 **Go CLI**。
2
+
3
+ 我下面统一使用 **`awiki-cli`** 作为最终命令名和主二进制名;项目名仍保持 awiki 体系,skill 命名继续保留 `awiki-*`。
4
+
5
+ ---
6
+
7
+ # awiki-cli v2 最终可执行方案(Go 版)
8
+
9
+ ## 1. 定版目标
10
+
11
+ awiki-cli v2 的目标不是“把旧 Python 脚本逐个翻译成 Go”,而是建立一个**对 AI 和人都稳定可路由的任务模型**:
12
+
13
+ * 按**用户意图**组织,而不是按脚本实现组织。
14
+ * 命令默认**非交互**。
15
+ * 所有有副作用的命令都支持 `--dry-run`。
16
+ * 所有命令都支持**结构化输出**。
17
+ * 提供可机器读取的 `schema`。
18
+ * skill 拆成 `shared + domain`,不再把所有内容塞进一个巨型 `SKILL.md`。
19
+
20
+ 这次语言切换到 Go 后,**命令契约不变**,变的是实现和发布:
21
+
22
+ * 命令树、参数语义、shortcut 规则、输出协议,保持 v2 设计;
23
+ * 实现层改成 Go;
24
+ * 发布改成多平台原生二进制;
25
+ * 文档、schema、shell completion、man page 从代码自动生成。
26
+
27
+ ---
28
+
29
+ ## 2. 产品边界与核心模型
30
+
31
+ ### 2.1 核心能力
32
+
33
+ CLI 的主线只有三块:
34
+
35
+ * `id`:身份生命周期
36
+ * `msg`:消息生命周期
37
+ * `runtime`:运行时与接收机制
38
+
39
+ 辅助命令:
40
+
41
+ * `status`
42
+ * `schema`
43
+ * `doctor`
44
+ * `docs`
45
+ * `version`
46
+ * `completion`
47
+
48
+ 扩展能力单独分组:
49
+
50
+ * `people`
51
+ * `page`
52
+ * `discovery`
53
+ * `debug`
54
+
55
+ ### 2.2 统一消息模型
56
+
57
+ 主文档里建议直接写死:
58
+
59
+ ```text
60
+ Message =
61
+ Target(scope: direct | group)
62
+ × Security(plain | e2ee)
63
+ × ReceiveMode(pull | realtime)
64
+ ```
65
+
66
+ 其中 AI 需要主动选择的只有:
67
+
68
+ * `scope`:私聊 / 群聊
69
+ * `security`:明文 / E2EE
70
+
71
+ `ReceiveMode` 属于 `runtime`,不属于 `msg` 路由。当前支持矩阵建议明确为:
72
+
73
+ ```text
74
+ direct + plain = supported
75
+ direct + e2ee = supported
76
+ group + plain = supported
77
+ group + e2ee = not supported yet
78
+ ```
79
+
80
+
81
+
82
+ ---
83
+
84
+ ## 3. 最终命令树
85
+
86
+ ## 3.1 canonical 命令树
87
+
88
+ 这是最终冻结的主命令树:
89
+
90
+ ```bash
91
+ awiki-cli status
92
+ awiki-cli docs [TOPIC]
93
+ awiki-cli schema [COMMAND]
94
+ awiki-cli doctor
95
+ awiki-cli version
96
+ awiki-cli init [--home PATH]
97
+ awiki-cli completion <bash|zsh|fish|powershell>
98
+
99
+ awiki-cli id status
100
+ awiki-cli id create --name "Alice" [--identity alice]
101
+ awiki-cli id register --handle alice (--phone +8613800138000 [--otp 123456] [--invite-code ABC123] | --email user@example.com [--wait]) [--identity alice]
102
+ awiki-cli id bind (--phone +8613800138000 [--otp 123456] | --email user@example.com [--wait]) [--identity alice]
103
+ awiki-cli id resolve (--handle alice | --did did:wba:...)
104
+ awiki-cli id recover --handle alice --phone +8613800138000 --otp 123456 [--identity alice]
105
+ awiki-cli id list
106
+ awiki-cli id current
107
+ awiki-cli id use alice
108
+ awiki-cli id profile get [--self | --handle alice | --did did:wba:...]
109
+ awiki-cli id profile set [--display-name "Alice"] [--bio "..."] [--tags "ai,did,agent"] [--markdown "# About Me"] [--markdown-file ./profile.md]
110
+
111
+ awiki-cli msg send (--to TARGET | --group GROUP_DID) [--text "Hello"] [--text-file ./message.txt] [--type text|event] [--secure off|on] [--identity alice]
112
+ awiki-cli msg inbox [--scope all|direct|group] [--with TARGET] [--group GROUP_DID] [--unread] [--limit 20] [--mark-read] [--identity alice]
113
+ awiki-cli msg history --with TARGET [--limit 50] [--cursor CURSOR] [--identity alice]
114
+ awiki-cli msg mark-read MSG_ID...
115
+
116
+ awiki-cli group create --name "Agent War Room" [--description "..."] [--discoverability private|listed|public] [--admission-mode admin-add|open-join] [--slug agent-war-room] [--goal "..."] [--rules "..."] [--message-prompt "..."] [--doc-url "https://..."] [--attachments-allowed] [--max-members 500] [--member-max-messages 10] [--member-max-total-chars 2000] [--identity alice]
117
+ awiki-cli group get --group GROUP_DID [--identity alice]
118
+ awiki-cli group join --group GROUP_DID [--reason "..."] [--identity alice]
119
+ awiki-cli group add --group GROUP_DID --member did:wba:... [--role member|admin] [--reason "..."] [--identity alice]
120
+ awiki-cli group remove --group GROUP_DID --member did:wba:... [--reason "..."] [--identity alice]
121
+ awiki-cli group members --group GROUP_DID [--limit 100] [--identity alice]
122
+ awiki-cli group messages --group GROUP_DID [--limit 50] [--cursor CURSOR] [--identity alice]
123
+ awiki-cli group update --group GROUP_DID [--name "..."] [--description "..."] [--discoverability private|listed|public] [--admission-mode admin-add|open-join] [--slug "..."] [--goal "..."] [--rules "..."] [--message-prompt "..."] [--doc-url "https://..."] [--attachments-allowed=true|false] [--max-members 500] [--member-max-messages 10] [--member-max-total-chars 2000] [--identity alice]
124
+ awiki-cli group leave --group GROUP_DID [--identity alice]
125
+
126
+ 测试与示例约定:
127
+
128
+ - DID / Group DID 的 profile 段默认使用 `e1_...` 形式,例如 `did:wba:example.com:user:alice:e1_alice`、`did:wba:example.com:groups:demo:e1_group`。
129
+ - 不再新增裸 `:e1` 的测试 fixture 或命令示例。
130
+
131
+ awiki-cli msg secure status [--with TARGET] [--identity alice]
132
+ awiki-cli msg secure init --with TARGET [--identity alice]
133
+ awiki-cli msg secure repair --with TARGET [--identity alice]
134
+ awiki-cli msg secure failed [--identity alice]
135
+ awiki-cli msg secure retry OUTBOX_ID [--identity alice]
136
+ awiki-cli msg secure drop OUTBOX_ID [--identity alice]
137
+
138
+ awiki-cli runtime status [--identity NAME]
139
+ awiki-cli runtime setup [--mode http|websocket] [--identity NAME]
140
+ awiki-cli runtime mode get
141
+ awiki-cli runtime mode set http|websocket
142
+ awiki-cli runtime listener status
143
+ awiki-cli runtime listener install
144
+ awiki-cli runtime listener start
145
+ awiki-cli runtime listener stop
146
+ awiki-cli runtime listener restart
147
+ awiki-cli runtime listener uninstall
148
+ awiki-cli runtime heartbeat status
149
+ awiki-cli runtime heartbeat install [--every 15m]
150
+ awiki-cli runtime heartbeat run-once
151
+
152
+ awiki-cli people search "AI agent"
153
+ awiki-cli people follow TARGET
154
+ awiki-cli people unfollow TARGET
155
+ awiki-cli people status TARGET
156
+ awiki-cli people followers
157
+ awiki-cli people following
158
+ awiki-cli people contacts list
159
+ awiki-cli people contacts save --did DID --handle HANDLE --reason "..."
160
+
161
+ awiki-cli page create --slug jd --title "Hiring" --markdown-file ./jd.md [--visibility public|draft|unlisted]
162
+ awiki-cli page list
163
+ awiki-cli page get --slug jd
164
+ awiki-cli page update --slug jd [--title "..."] [--markdown "..."] [--markdown-file ./x.md] [--visibility public|draft|unlisted]
165
+ awiki-cli page rename --slug jd --to hiring
166
+ awiki-cli page delete --slug hiring
167
+
168
+ awiki-cli discovery scan --group GROUP_ID
169
+ awiki-cli discovery recommend --group GROUP_ID
170
+ awiki-cli discovery draft-intro --group GROUP_ID
171
+ awiki-cli discovery draft-dm --group GROUP_ID --member DID
172
+
173
+ awiki-cli debug db query "SELECT ..."
174
+ awiki-cli debug raw rpc ...
175
+ awiki-cli debug schema-cache
176
+ awiki-cli debug logs [--follow]
177
+ ```
178
+
179
+ 这棵树延续了两份文档的核心设计:`status / docs / schema / doctor / id / msg / runtime` 作为核心,`people / page / discovery / debug` 作为扩展;其中**所有发送动作都统一收敛到 `msg send`**,不再按“私聊脚本 / 群发脚本 / E2EE 脚本”分裂。
180
+
181
+ ## 3.2 新增的 Go 标准命令
182
+
183
+ 相比原草案,我建议在 Go 版里正式加入:
184
+
185
+ ```bash
186
+ awiki-cli docs [TOPIC]
187
+ awiki-cli init [--home PATH]
188
+ awiki-cli completion <bash|zsh|fish|powershell>
189
+ ```
190
+
191
+ `docs` 作为一级命令,用于承载 onboarding、identity、secure-messaging、transport-modes 等产品内建文档。
192
+
193
+ `init` 作为显式初始化命令,用于:
194
+
195
+ * 帮用户创建工作目录(默认是 `~/.awiki-cli`,或由 `AWIKI_HOME` 指定)及其子目录;
196
+ * 在首次需要时生成一份最小的 `config.json` 骨架;
197
+
198
+ Cobra 本身就是面向现代 Go CLI 的命令树框架,支持子命令、flag、自动 help;官方文档也明确支持 shell completion,以及从命令树生成 Markdown/man page 文档。用它来做 awiki-cli,正好能把命令、帮助、completion、文档和 LLM 索引统一起来。([GitHub][1])
199
+
200
+ ---
201
+
202
+ ## 4. shortcut 设计
203
+
204
+ shortcut 要加,但**只能是 canonical command 的别名**,不能形成第二套语义。这个原则保留。
205
+
206
+ 建议保留 8 个以内:
207
+
208
+ ```bash
209
+ awiki-cli setup # = awiki-cli runtime setup
210
+ awiki-cli register ... # = awiki-cli id register ...
211
+ awiki-cli whoami # = awiki-cli id current
212
+ awiki-cli inbox # = awiki-cli msg inbox
213
+ awiki-cli dm alice "hello" # = awiki-cli msg send --to alice --text "hello"
214
+ awiki-cli secure alice "secret" # = awiki-cli msg send --to alice --text "secret" --secure on
215
+ awiki-cli group get --group did:wba:... # top-level canonical group lifecycle entry
216
+ awiki-cli history alice # = awiki-cli msg history --with alice
217
+ ```
218
+
219
+ 最终规则:
220
+
221
+ * shortcut 只能是 alias
222
+ * shortcut 不能有独占语义
223
+ * shortcut 数量控制在 6–8 个
224
+ * 文档先写 canonical,再写 shortcut
225
+ * 不引入飞书那种 `+xxx` 作为主语法
226
+
227
+ 另外,**canonical 命令默认 JSON,shortcut 默认 pretty/table**。这点保留 output-format 的结论:协议层以 JSON 为主,展示层可以更友好。
228
+
229
+ ---
230
+
231
+ ## 5. 参数命名与冲突收敛
232
+
233
+ 这里我把两份文档里不一致的地方做了统一。
234
+
235
+ ## 5.1 全局参数
236
+
237
+ 最终定为:
238
+
239
+ ```bash
240
+ --identity <name> # canonical
241
+ --credential <name> # legacy alias
242
+
243
+ --format json|pretty|table|ndjson
244
+ --output ... # legacy alias of --format
245
+ --json # alias of --format json
246
+ --jq '<expr>'
247
+ --dry-run
248
+ --yes
249
+ --verbose
250
+ --no-color
251
+ ```
252
+
253
+ 这样做有两个好处:
254
+
255
+ 第一,把 `cli-init.md` 里的 `--output` 和 `output-format.md` 里的 `--format` 收敛到一个最终名字:**`--format`**。
256
+ 第二,把 `human` 收敛成 `pretty`;如果你还想兼容旧写法,可以把 `human` 当成 `pretty` 的 deprecated alias。
257
+
258
+ ## 5.2 目标与身份参数
259
+
260
+ ```bash
261
+ --to <handle|did>
262
+ --group <group-id>
263
+ --did <did>
264
+ --handle <handle>
265
+ --with <target>
266
+ ```
267
+
268
+ 规则:
269
+
270
+ * 发消息只用 `--to` 或 `--group`
271
+ * 历史、secure peer 用 `--with`
272
+ * 只有显式解析场景才用 `--did` / `--handle`
273
+ * `--peer`、`--target-did` 不再扩散
274
+
275
+ ## 5.3 内容参数
276
+
277
+ ```bash
278
+ --text "..."
279
+ --text-file ./message.txt
280
+
281
+ --markdown "..."
282
+ --markdown-file ./doc.md
283
+ ```
284
+
285
+ 规则:
286
+
287
+ * 消息一律 `--text`
288
+ * Markdown 一律 `--markdown`
289
+ * 不再混用 `--content` / `--body` / `--profile-md`
290
+
291
+ ## 5.4 控制参数
292
+
293
+ ```bash
294
+ --secure off|on
295
+ --mode http|websocket
296
+ --wait
297
+ --limit 50
298
+ --cursor CURSOR
299
+ --force
300
+ ```
301
+
302
+ `--wait` 只允许轮询,不允许 CLI 内部 prompt;CLI 仍然保持非交互默认。
303
+
304
+ ---
305
+
306
+ ## 6. 返回协议:JSON 为契约,pretty/table/ndjson 为视图
307
+
308
+ 这里按 `output-format.md` 直接定版:**CLI 的标准返回是 JSON,自然语言只是 JSON 里的字段,不是命令契约本身。** `pretty`、`table`、`ndjson` 都是 JSON 的渲染形式。
309
+
310
+ ## 6.1 默认输出规则
311
+
312
+ * canonical command:默认 `--format json`
313
+ * shortcut:默认 `--format pretty` 或 `table`
314
+ * 流式命令:只允许 `--format ndjson`
315
+
316
+ ## 6.2 成功/失败统一信封
317
+
318
+ 我建议最终 Go 代码里统一成这一套:
319
+
320
+ ```json
321
+ {
322
+ "ok": true,
323
+ "command": "awiki-cli msg send",
324
+ "data": {},
325
+ "warnings": [],
326
+ "summary": "",
327
+ "_notice": {},
328
+ "meta": {
329
+ "version": "2.0.0",
330
+ "identity": {
331
+ "name": "alice",
332
+ "did": "did:wba:awiki.ai:user:abc...xyz"
333
+ },
334
+ "dry_run": false,
335
+ "format": "json"
336
+ }
337
+ }
338
+ ```
339
+
340
+ ```json
341
+ {
342
+ "ok": false,
343
+ "error": {
344
+ "code": "permission_denied",
345
+ "message": "Missing required permission",
346
+ "hint": "Run awiki-cli id use alice or refresh identity",
347
+ "retryable": false,
348
+ "details": {}
349
+ },
350
+ "_notice": {},
351
+ "meta": {
352
+ "version": "2.0.0",
353
+ "dry_run": false,
354
+ "format": "json"
355
+ }
356
+ }
357
+ ```
358
+
359
+ 这里我也做了一个冲突收敛:
360
+ `cli-init.md` 里有 `notice`,`output-format.md` 里用的是 `_notice`。最终建议统一为 **`_notice`**;`notice` 只在 legacy 模式兼容,不再作为新输出字段。
361
+
362
+ ## 6.3 命令类别与返回内容
363
+
364
+ 查询类命令返回**事实状态**:
365
+
366
+ * `status`
367
+ * `id status`
368
+ * `msg inbox`
369
+ * `msg history`
370
+ * `people search`
371
+
372
+ 写操作返回**发生了什么变更**:
373
+
374
+ * `id register`
375
+ * `msg send`
376
+ * `msg group join`
377
+ * `people follow`
378
+ * `page create`
379
+
380
+ 异步命令返回**任务状态**:
381
+
382
+ * `runtime setup`
383
+ * `listener install`
384
+ * `discovery scan`(如做异步)
385
+ * 大批量同步/发布
386
+
387
+ 流式命令一律 `ndjson`:
388
+
389
+ * `runtime listener logs --follow`
390
+ * 未来的 `msg watch`
391
+ * 未来的 `heartbeat watch`
392
+
393
+ 这部分保持 output-format 文档的原结论。
394
+
395
+ ## 6.4 `--dry-run`
396
+
397
+ 所有有副作用的命令都必须支持 `--dry-run`,并返回 `plan`。
398
+ `--dry-run` 时允许参数校验、本地只读检查、安全的 GET 预检;禁止发送 OTP、邮件、消息,禁止远端写入,禁止本地持久化。
399
+
400
+ ## 6.5 `--jq`
401
+
402
+ `--jq` 必须做,而且建议直接嵌入 `gojq`。`gojq` 官方仓库明确说明它是 jq 的纯 Go 实现,而且可以嵌入到 Go 产品里。对 awiki-cli 来说,这正好对应 `--jq` 的需求。([GitHub][2])
403
+
404
+ ## 6.6 错误码与退出码
405
+
406
+ 错误码集合定为:
407
+
408
+ ```text
409
+ invalid_argument
410
+ identity_required
411
+ auth_required
412
+ permission_denied
413
+ not_found
414
+ conflict
415
+ network_error
416
+ transport_unavailable
417
+ secure_session_required
418
+ unsupported_mode
419
+ partial_failure
420
+ internal_error
421
+ ```
422
+
423
+ 退出码定为:
424
+
425
+ ```text
426
+ 0 success
427
+ 1 generic error
428
+ 2 invalid argument
429
+ 3 identity/auth missing
430
+ 4 permission denied
431
+ 5 not found
432
+ 6 partial failure
433
+ 7 confirmation required but not provided
434
+ ```
435
+
436
+ ---
437
+
438
+ ## 7. `schema`:从“命令说明”升级成“机器契约”
439
+
440
+ `schema` 不是文档别名,而是**命令元数据接口**。这是两份文档里最值得保留的设计之一。
441
+
442
+ 最终形态:
443
+
444
+ ```bash
445
+ awiki-cli schema
446
+ awiki-cli schema msg.send
447
+ awiki-cli schema id.register
448
+ awiki-cli schema runtime.listener.install
449
+ awiki-cli schema --skills
450
+ ```
451
+
452
+ 返回结构至少包括:
453
+
454
+ ```json
455
+ {
456
+ "name": "awiki-cli msg send",
457
+ "summary": "Send a direct or group message",
458
+ "aliases": ["awiki-cli dm"],
459
+ "side_effect": true,
460
+ "confirm_required": false,
461
+ "dry_run_supported": true,
462
+ "identity_required": true,
463
+ "output_formats": ["json", "pretty", "table", "ndjson"],
464
+ "capabilities": {
465
+ "direct_plain": true,
466
+ "direct_e2ee": true,
467
+ "group_plain": true,
468
+ "group_e2ee": false
469
+ },
470
+ "args": [],
471
+ "returns": {},
472
+ "errors": [],
473
+ "examples": [],
474
+ "legacy_maps_to": [
475
+ "scripts/send_message.py",
476
+ "scripts/e2ee_messaging.py --send",
477
+ "scripts/manage_group.py --post-message"
478
+ ]
479
+ }
480
+ ```
481
+
482
+ 最终文件布局:
483
+
484
+ ```text
485
+ schemas/
486
+ cli.json
487
+ commands/
488
+ awiki-cli.status.json
489
+ awiki-cli.id.register.json
490
+ awiki-cli.msg.send.json
491
+ awiki-cli.msg.group.join.json
492
+ awiki-cli.runtime.setup.json
493
+ ```
494
+
495
+ 并且要求:
496
+
497
+ * `awiki-cli schema` 从代码内的 command registry 直接生成
498
+ * `CLI_REFERENCE.md` 从 schema 生成
499
+ * `skills/*/SKILL.md` 中的命令引用由 CI 校验
500
+ * shell help、Markdown docs、man pages 一起自动生成
501
+
502
+ Cobra 官方现在已经明确支持从命令树生成 Markdown/man page,并专门有 “LLM-ready CLI docs” 的文档路径;这非常适合 awiki-cli 把命令树、skill 文档和 schema 保持同步。([cobra.dev][3])
503
+
504
+ ---
505
+
506
+ ## 8. Go 实现架构
507
+
508
+ ## 8.1 技术选型
509
+
510
+ 我建议 Go 版固定为这套:
511
+
512
+ * 命令树:**Cobra**
513
+ * JSON 编码:标准库 `encoding/json`
514
+ * `--jq`:**gojq**
515
+ * 发布:**GoReleaser**
516
+ * GitHub Actions 发布:**goreleaser-action**
517
+ * 后台 listener/service:**kardianos/service**
518
+ * 本地 SQLite:**modernc.org/sqlite**(默认 pure Go 方案)
519
+
520
+ Cobra 官方仓库把它定义为“用于现代 Go CLI 的命令框架”,并且是 Kubernetes、Hugo、GitHub CLI 等项目在用的同类方案;它天然适合 awiki-cli 这种深层子命令树。([GitHub][1])
521
+
522
+ GoReleaser 官方把自己定位为“简化发布工程”,而 `goreleaser-action` 则直接给出了 tag 触发发布、上传 artifacts、签名等 CI 模式,正适合 awiki-cli 的多平台二进制分发。([GitHub][4])
523
+
524
+ `kardianos/service` 官方 README 明确说明它可以用同一套 API 在 Windows、Linux(systemd/Upstart/SysV)和 macOS Launchd 上安装、启动、停止服务,这正好对应 `runtime listener install/start/stop/uninstall`。([GitHub][5])
525
+
526
+ `modernc.org/sqlite` 是 CGo-free 的 SQLite 驱动,并明确列出 darwin/linux/windows 多平台支持;对一个要靠 GoReleaser 做多平台发布的 CLI 来说,这比强依赖 CGO 的方案更稳。([Go Packages][6])
527
+
528
+ ## 8.2 工程目录
529
+
530
+ 我建议 repo 最终长这样:
531
+
532
+ ```text
533
+ .
534
+ ├── cmd/
535
+ │ └── awiki-cli/
536
+ │ └── main.go
537
+ ├── internal/
538
+ │ ├── cli/
539
+ │ │ ├── root.go
540
+ │ │ ├── globalflags/
541
+ │ │ ├── shortcuts/
542
+ │ │ ├── render/
543
+ │ │ ├── schema/
544
+ │ │ └── commands/
545
+ │ │ ├── status/
546
+ │ │ ├── doctor/
547
+ │ │ ├── id/
548
+ │ │ ├── msg/
549
+ │ │ ├── runtime/
550
+ │ │ ├── people/
551
+ │ │ ├── page/
552
+ │ │ ├── discovery/
553
+ │ │ └── debug/
554
+ │ ├── app/
555
+ │ │ ├── identity/
556
+ │ │ ├── messaging/
557
+ │ │ ├── runtime/
558
+ │ │ ├── people/
559
+ │ │ ├── page/
560
+ │ │ └── discovery/
561
+ │ ├── transport/
562
+ │ │ ├── http/
563
+ │ │ └── websocket/
564
+ │ ├── store/
565
+ │ │ ├── sqlite/
566
+ │ │ ├── credentials/
567
+ │ │ └── migrations/
568
+ │ ├── legacy/
569
+ │ └── security/
570
+ ├── skills/
571
+ │ ├── awiki-bundle/
572
+ │ ├── awiki-shared/
573
+ │ ├── awiki-id/
574
+ │ ├── awiki-msg/
575
+ │ ├── awiki-runtime/
576
+ │ ├── awiki-people/
577
+ │ ├── awiki-discovery/
578
+ │ ├── awiki-page/
579
+ │ └── awiki-debug/
580
+ ├── references/
581
+ ├── schemas/
582
+ ├── docs/
583
+ │ └── cli/
584
+ ├── .goreleaser.yaml
585
+ ├── Makefile
586
+ └── go.mod
587
+ ```
588
+
589
+ 这里 skill 目录我建议**继续保留 `awiki-*` 命名**,因为现有 skill 和服务生态都还是 awiki;CLI 命令名统一改成 `awiki-cli`,避免与项目名、skill 名和服务域混淆。
590
+
591
+ ## 8.3 代码分层
592
+
593
+ 强制遵守这条规则:
594
+
595
+ * Cobra command 层只负责参数解析、校验、调用 handler
596
+ * handler 只返回**typed result**
597
+ * 所有 stdout/stderr 输出统一走 renderer
598
+ * 业务层不直接打印
599
+ * `schema`、help、docs、skill 引用全部来自统一 registry
600
+
601
+ 这能避免最常见的 CLI 漂移:代码、help、docs、skill 四套说法各自为政。
602
+
603
+ ## 8.4 推荐的核心 Go 类型
604
+
605
+ 建议从一开始就把“输出契约”和“schema 契约”写成显式类型:
606
+
607
+ ```go
608
+ type Envelope[T any] struct {
609
+ OK bool `json:"ok"`
610
+ Command string `json:"command"`
611
+ Data *T `json:"data,omitempty"`
612
+ Error *ErrBody `json:"error,omitempty"`
613
+ Warnings []Warning `json:"warnings,omitempty"`
614
+ Summary string `json:"summary,omitempty"`
615
+ Notice *Notice `json:"_notice,omitempty"`
616
+ Meta Meta `json:"meta"`
617
+ }
618
+
619
+ type ErrBody struct {
620
+ Code string `json:"code"`
621
+ Message string `json:"message"`
622
+ Hint string `json:"hint,omitempty"`
623
+ Retryable bool `json:"retryable"`
624
+ Details map[string]any `json:"details,omitempty"`
625
+ }
626
+
627
+ type CommandSpec struct {
628
+ Name string `json:"name"`
629
+ Aliases []string `json:"aliases,omitempty"`
630
+ Summary string `json:"summary"`
631
+ SideEffect bool `json:"side_effect"`
632
+ ConfirmRequired bool `json:"confirm_required"`
633
+ DryRunSupported bool `json:"dry_run_supported"`
634
+ IdentityRequired bool `json:"identity_required"`
635
+ OutputFormats []string `json:"output_formats"`
636
+ Args []ArgSpec `json:"args,omitempty"`
637
+ Returns ReturnSpec `json:"returns"`
638
+ Errors []ErrorSpec `json:"errors,omitempty"`
639
+ Examples []string `json:"examples,omitempty"`
640
+ LegacyMapsTo []string `json:"legacy_maps_to,omitempty"`
641
+ }
642
+ ```
643
+
644
+ ---
645
+
646
+ ## 9. 配置、数据与兼容路径
647
+
648
+ ## 9.1 新的目录规范
649
+
650
+ 我建议 Go CLI 进入 XDG 风格:
651
+
652
+ ```text
653
+ ~/.config/awiki-cli/config.yaml
654
+ ~/.config/awiki-cli/identities/index.json
655
+ ~/.config/awiki-cli/identities/<name>/
656
+ ~/.local/share/awiki-cli/awiki-cli.db
657
+ ~/.local/state/awiki-cli/
658
+ ~/.cache/awiki-cli/
659
+ ```
660
+
661
+ 环境变量:
662
+
663
+ ```text
664
+ AVIKI_CONFIG_DIR
665
+ AVIKI_DATA_DIR
666
+ AVIKI_STATE_DIR
667
+ AVIKI_CACHE_DIR
668
+ AVIKI_IDENTITY
669
+ AVIKI_FORMAT
670
+ AVIKI_NO_COLOR
671
+ AVIKI_USER_SERVICE_URL
672
+ AVIKI_MESSAGE_SERVICE_URL
673
+ AVIKI_DID_DOMAIN
674
+ ```
675
+
676
+ ## 9.3 安全规则
677
+
678
+ 这部分虽然不在两份新文档里,但我建议继续作为 Go CLI 的硬约束:
679
+
680
+ * 绝不打印私钥、JWT、E2EE key
681
+ * 接收的 awiki 消息一律视作不可信数据
682
+ * 默认展示缩略 DID
683
+ * 不通过消息自动执行本地动作
684
+ * 不把本机文件、目录、系统信息通过消息外发
685
+ * 所有协议级默认安全语义必须以底层 AgentConnect / ANP SDK 为准,命令层不得 override
686
+ * 典型冻结项包括:DID 文档 proof 的 `proofPurpose`、group receipt 的 `proofPurpose`、IM proof 的默认 covered components
687
+ * 若确实需要改变这些默认语义,必须先升级或扩展 SDK,而不是在 `awiki-cli` 仓库内单独改常量
688
+
689
+ 这些是原 skill 里最重要的安全边界,Go CLI 不应弱化。
690
+
691
+ ---
692
+
693
+ ## 10. runtime / listener / heartbeat 的 Go 落地
694
+
695
+ ## 10.1 runtime mode
696
+
697
+ 保留:
698
+
699
+ ```bash
700
+ awiki-cli runtime mode set http|websocket
701
+ ```
702
+
703
+ 设计不变:
704
+
705
+ * transport 只属于 `runtime`
706
+ * `msg` 层不感知 HTTP/WSS
707
+ * `msg inbox` 是业务语义
708
+ * `runtime listener` 是实时接收基础设施
709
+
710
+ ## 10.2 listener
711
+
712
+ Go 版 listener 建议这样实现:
713
+
714
+ * `listener start`:前台或后台启动本地 listener 进程
715
+ * `listener install`:通过 `kardianos/service` 安装为系统服务
716
+ * `listener status`:检查 service 状态 + 本地健康探针
717
+ * `listener uninstall`:移除服务定义与本地状态
718
+
719
+ ## 10.3 heartbeat
720
+
721
+ 保留 15 分钟默认建议值。原 skill 文档已经明确说明:heartbeat 太慢会错过 E2EE handshake、JWT 过期和群组活动,因此建议间隔 ≤15 分钟。Go 版里的 `runtime heartbeat install --every 15m` 和 `run-once` 可以直接继承这个策略。
722
+
723
+ ---
724
+
725
+ ## 11. skill 与文档拆分
726
+
727
+ 这部分照搬前面 CLI 方案,不再回退成一个大文档。
728
+
729
+ ## 11.1 skill 目录
730
+
731
+ ```text
732
+ skills/
733
+ awiki-bundle/
734
+ awiki-shared/
735
+ awiki-id/
736
+ awiki-msg/
737
+ awiki-runtime/
738
+ awiki-people/
739
+ awiki-discovery/
740
+ awiki-page/
741
+ awiki-debug/
742
+ ```
743
+
744
+ 职责分别是:
745
+
746
+ * `awiki-bundle`:只做导航
747
+ * `awiki-shared`:共享规则、安全、输出协议、schema、dry-run、确认规则
748
+ * `awiki-id`:身份
749
+ * `awiki-msg`:消息
750
+ * `awiki-runtime`:listener / heartbeat / mode
751
+ * `awiki-people`:search/follow/contacts
752
+ * `awiki-discovery`:群发现工作流
753
+ * `awiki-page`:内容页
754
+ * `awiki-debug`:raw/debug/db
755
+
756
+ ## 11.2 references 目录
757
+
758
+ ```text
759
+ references/
760
+ SECURITY.md
761
+ CLI_REFERENCE.md
762
+ IDENTITY.md
763
+ MESSAGING.md
764
+ RUNTIME.md
765
+ PEOPLE.md
766
+ DISCOVERY.md
767
+ PAGE.md
768
+ DEBUG.md
769
+ UPGRADE.md
770
+ WHY_AWIKI.md
771
+ ```
772
+
773
+ 原则不变:
774
+
775
+ * 一个主题只有一个权威文档
776
+ * `SKILL.md` 只做路由与默认行为
777
+ * CLI 细节全部下沉到 `CLI_REFERENCE.md`
778
+ * discovery 不再挤占 `msg` 主路径
779
+
780
+ ---
781
+
782
+ ## 12. 旧脚本迁移映射
783
+
784
+ 这一部分直接保留,但目标从 Python wrapper 改成 Go CLI:
785
+
786
+ ```text
787
+ scripts/check_status.py -> awiki-cli status
788
+ scripts/setup_identity.py -> awiki-cli id create / id list / id use
789
+ scripts/send_verification_code.py -> awiki-cli id register / id bind
790
+ scripts/register_handle.py -> awiki-cli id register
791
+ scripts/bind_contact.py -> awiki-cli id bind
792
+ scripts/resolve_handle.py -> awiki-cli id resolve
793
+ scripts/recover_handle.py -> awiki-cli id recover
794
+ scripts/get_profile.py -> awiki-cli id profile get
795
+ scripts/update_profile.py -> awiki-cli id profile set
796
+ scripts/send_message.py -> awiki-cli msg send --secure off
797
+ scripts/e2ee_messaging.py --send -> awiki-cli msg send --secure on
798
+ scripts/check_inbox.py -> awiki-cli msg inbox / msg history / msg mark-read
799
+ scripts/manage_group.py -> awiki-cli msg group ...
800
+ scripts/manage_group.py --post-message -> awiki-cli msg send --group ...
801
+ scripts/setup_realtime.py -> awiki-cli runtime setup
802
+ scripts/ws_listener.py -> awiki-cli runtime listener ...
803
+ scripts/query_db.py -> awiki-cli debug db query
804
+ ```
805
+
806
+ 这层映射建议做成:
807
+
808
+ * `legacy/` 中的兼容说明
809
+ * `schema` 里的 `legacy_maps_to`
810
+ * `doctor` 的迁移提示
811
+ * 旧脚本执行时输出 deprecation hint
812
+
813
+ 这部分正是 `cli-init.md` 里最适合直接继承的内容。
814
+
815
+ ---
816
+
817
+ ## 13. 包发布与安装
818
+
819
+ 既然已经切到 Go,我建议发布路径也跟着定:
820
+
821
+ ## 13.1 首发方式
822
+
823
+ 首发只做:
824
+
825
+ * GitHub Releases
826
+ * npm wrapper(`@awiki/cli`)
827
+ * 多平台二进制:
828
+
829
+ * macOS: amd64 / arm64
830
+ * Linux: amd64 / arm64
831
+ * Windows: amd64 / arm64
832
+ * checksum
833
+ * shell completions
834
+ * man pages
835
+ * `docs/cli` Markdown 文档
836
+
837
+ GoReleaser 和它的 GitHub Action 已经把 tag 触发发布、上传 artifacts、签名和产物输出说明得很清楚,适合作为标准发布链路。([GitHub][4])
838
+
839
+ ## 13.2 安装方式
840
+
841
+ 建议四种:
842
+
843
+ ```bash
844
+ # 1) 直接下载 release 压缩包
845
+ # 2) npm install -g @awiki/cli
846
+ # 3) curl 安装脚本(官方自建)
847
+ # 4) go install(仅开发者/高级用户)
848
+ go install github.com/AgentConnect/awiki-cli/cmd/awiki-cli@latest
849
+ ```
850
+
851
+ 首发阶段直接支持 **npm wrapper**。
852
+ 推荐同时提供 GitHub Releases、npm wrapper 和 `go install`:人类用户可以走 npm / release,开发者和 CI 可以直接走原生二进制或 `go install`。
853
+
854
+ ## 13.3 发布文件
855
+
856
+ 建议发布这些:
857
+
858
+ ```text
859
+ awiki-cli_Darwin_x86_64.tar.gz
860
+ awiki-cli_Darwin_arm64.tar.gz
861
+ awiki-cli_Linux_x86_64.tar.gz
862
+ awiki-cli_Linux_arm64.tar.gz
863
+ awiki-cli_Windows_x86_64.zip
864
+ awiki-cli_Windows_arm64.zip
865
+ checksums.txt
866
+ npm/
867
+ awiki-cli.bash
868
+ awiki-cli.zsh
869
+ awiki-cli.fish
870
+ awiki-cli.ps1
871
+ manpages/
872
+ docs/cli/
873
+ ```
874
+
875
+ ---
876
+
877
+ ## 14. 开发与测试计划
878
+
879
+ 为了让这个方案真的能落地,我建议按 4 个阶段做。
880
+
881
+ ## Phase 1:冻结契约
882
+
883
+ 先只做:
884
+
885
+ * root command tree
886
+ * `status / docs / schema / doctor / id / msg / runtime`
887
+ * 全局 flags
888
+ * JSON envelope
889
+ * `--format`
890
+ * `--dry-run`
891
+ * `--jq`
892
+ * `schema`
893
+ * `completion`
894
+
895
+ 这个阶段重点是**命令契约稳定**,不是功能全做完。
896
+
897
+ ## Phase 2:把 core 跑通
898
+
899
+ 实现:
900
+
901
+ * identity create/register/bind/resolve/recover/profile
902
+ * direct/group send/inbox/history
903
+ * secure send/init/repair/retry/drop
904
+ * runtime mode/listener/heartbeat
905
+ * SQLite store
906
+ * legacy import
907
+
908
+ ## Phase 3:扩展命令
909
+
910
+ 实现:
911
+
912
+ * people
913
+ * page
914
+ * discovery
915
+ * debug
916
+
917
+ ## Phase 4:自动化与文档闭环
918
+
919
+ 补齐:
920
+
921
+ * docs/cli 自动生成
922
+ * skill 引用校验
923
+ * shell completion
924
+ * man page
925
+ * release pipeline
926
+ * golden tests / integration tests / migration tests
927
+
928
+ ---
929
+
930
+ ## 15. 最终定版结论
931
+
932
+ 我建议你直接按下面 10 条拍板:
933
+
934
+ 1. **命令名与主二进制名统一定为 `awiki-cli`。**
935
+ 2. **canonical CLI 定为:**
936
+ `status / docs / schema / doctor / version / completion / id / msg / runtime`
937
+ 3. **消息发送统一入口:**
938
+ `awiki-cli msg send`
939
+ 4. **transport 只属于 runtime,msg 层不感知 HTTP/WSS。**
940
+ 5. **shortcut 要加,但只做 alias,不做 `+` 第二语法。**
941
+ 6. **标准返回是 JSON;pretty/table/ndjson 都是视图。**
942
+ 7. **全局格式参数统一为 `--format`;`--output` 仅做兼容别名。**
943
+ 8. **`schema`、`--dry-run`、`--jq` 必须是第一天就有的一等能力。**
944
+ 9. **Go 技术栈固定为:Cobra + gojq + GoReleaser + kardianos/service + modernc.org/sqlite。**
945
+ 10. **skill 和文档按 `shared + domain` 拆分,同时分发支持 GitHub Releases + npm wrapper。** ([GitHub][1])
946
+
947
+ 如果你要,我下一步可以直接继续给你两份可落地内容:
948
+ **1)`cmd/awiki-cli` 的 Go 项目目录初始化方案**,以及 **2)`CLI_REFERENCE.md` 的最终文档定稿**。
949
+
950
+ [1]: https://github.com/spf13/cobra "GitHub - spf13/cobra: A Commander for modern Go CLI interactions · GitHub"
951
+ [2]: https://github.com/itchyny/gojq "GitHub - itchyny/gojq: Pure Go implementation of jq · GitHub"
952
+ [3]: https://cobra.dev/docs/how-to-guides/clis-for-llms/?utm_source=chatgpt.com "Generate LLM‑Ready CLI Docs with Cobra"
953
+ [4]: https://github.com/goreleaser/goreleaser "GitHub - goreleaser/goreleaser: Release engineering, simplified · GitHub"
954
+ [5]: https://github.com/kardianos/service?utm_source=chatgpt.com "kardianos/service: Run go programs as ..."
955
+ [6]: https://pkg.go.dev/modernc.org/sqlite "sqlite package - modernc.org/sqlite - Go Packages"