@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,903 @@
1
+ # awiki-cli v2 落地实施规划
2
+
3
+ **文档状态**:Draft v1.0
4
+ **文档用途**:把架构设计转成可执行的工程实施计划,作为后续拆解里程碑、Issue、子任务和验收的基线。
5
+ **适用范围**:`awiki-cli` Go 重写、命令面收敛、SQLite/凭证迁移、runtime/listener、skills/docs/schema、发布切换。
6
+ **最后更新**:2026-04-07
7
+
8
+ > **Phase 0 冻结结果说明**:`docs/plan/phase-0/` 下的冻结文档是后续实现的直接约束。当本文与 Phase 0 冻结文档冲突时,以 Phase 0 冻结文档为准。
9
+
10
+ ---
11
+
12
+ ## 1. 目标与输入基线
13
+
14
+ 本文档不再讨论“是否要重写”或“是否继续 Python”。这些决策已经在架构文档中冻结。本文档只回答一个问题:
15
+
16
+ **如何把 awiki v2 的目标架构按可交付、可验收、可迁移的方式实现出来。**
17
+
18
+ ### 1.1 实施目标
19
+
20
+ awiki-cli v2 的实施目标是:
21
+
22
+ 1. 把当前脚本集合收敛成统一的 `awiki-cli` 产品面。
23
+ 2. 把 `id / msg / group / runtime` 做成首批可用的稳定域。
24
+ 3. 保留 awiki 的差异化能力:DID、多身份、本地状态、E2EE、显式 runtime mode、group/relationship 沉淀。
25
+ 4. 让 CLI、docs、schema、doctor、skills 不再分裂,转成单一元数据驱动的产品体系。
26
+ 5. 提供从 `../awiki-agent-id-message/` 到 v2 的凭证、SQLite、本地 runtime 配置迁移路径。
27
+
28
+ ### 1.2 本次规划的输入文档与代码基线
29
+
30
+ | 类别 | 路径 | 用途 |
31
+ |---|---|---|
32
+ | 总体架构 | `docs/architecture/awiki-v2-architecture.md` | v2 总体分层、域模型、runtime、安全、发布 |
33
+ | 命令与执行方案 | `docs/architecture/awiki-command-v2.md` | 最终命令树、参数、输出、目录、阶段划分 |
34
+ | 输出契约 | `docs/architecture/output-format.md` | JSON envelope、dry-run、schema、exit code |
35
+ | 飞书 CLI 参考 | `../cli/` | Cobra 命令组织、schema/doctor/completion、skills、shortcuts、发布 |
36
+ | awiki v1 Python CLI 参考 | `../awiki-agent-id-message/` | 能力映射、listener/runtime、本地 SQLite、凭证布局、迁移逻辑 |
37
+ | 用户服务 API | `../user-service/docs/api/` | 身份、handle、profile、relationships、group |
38
+ | 消息服务 API | `../message-service/docs/api/` | direct/group/attachment、local view、WS 通知 |
39
+
40
+ ### 1.3 发生冲突时的优先级
41
+
42
+ 实现时按照下面的优先级裁决:
43
+
44
+ 1. `docs/architecture/awiki-command-v2.md`
45
+ 2. `docs/architecture/awiki-v2-architecture.md`
46
+ 3. `docs/architecture/output-format.md`
47
+ 4. `../user-service/docs/api/` 与 `../message-service/docs/api/`
48
+ 5. `../awiki-agent-id-message/`
49
+ 6. `../cli/`
50
+
51
+ > 说明:`../awiki-agent-id-message/` 是实现参考与迁移基线,不是 v2 命令契约的最终真相。
52
+
53
+ ---
54
+
55
+ ## 2. 规划前先冻结的决定
56
+
57
+ 本节是实施前必须明确、不允许实现阶段再反复摇摆的决定。
58
+
59
+ ### 2.1 产品与命令冻结
60
+
61
+ - 主二进制名固定为:`awiki-cli`
62
+ - canonical 顶级命令固定为:
63
+ - `status`
64
+ - `docs`
65
+ - `schema`
66
+ - `doctor`
67
+ - `version`
68
+ - `completion`
69
+ - `config`
70
+ - `id`
71
+ - `msg`
72
+ - `group`
73
+ - `runtime`
74
+ - `people`
75
+ - `page`
76
+ - `debug`
77
+ - 发消息唯一 canonical 入口固定为:`awiki-cli msg send`
78
+ - transport 只允许出现在 `runtime` 域,不允许泄漏到 `msg` / `group` 命令参数面。
79
+
80
+ ### 2.2 术语冻结
81
+
82
+ - 用户层主术语使用 **identity**。
83
+ - `credential` 仅作为兼容 v1 的内部实现术语或 alias,不再作为 v2 主文案。
84
+ - 本地数据隔离主键继续使用 `owner_did`。
85
+
86
+ ### 2.3 User 生命周期冻结
87
+
88
+ - **handle 是对外用户主流程的必填项。**
89
+ - **v2 首版不支持 pure DID 作为对外用户完成态。**
90
+ - **对外公共身份标识只使用 handle;`did` 仅在协议级定位需要时出现;`user_id` 为内部字段,不对 CLI / docs / schema / 输出透出。**
91
+ - `id create` 只保留为本地 bootstrap / 迁移辅助能力,不作为消息、runtime、群组主链路的前置完成态;默认从公开 help 中隐藏。
92
+ - 用户完成态固定定义为:**本地 DID 材料已生成 + 远端 user 已创建 + handle 已创建或恢复 + 本地凭证已记录**。
93
+ - `id register` / `id recover` 是进入可用用户态的 canonical 入口;`msg` 与 `runtime listener` 默认要求当前 identity 已完成该用户态。
94
+
95
+ ### 2.4 输出与全局参数冻结
96
+
97
+ - 全局格式参数统一为:`--format`
98
+ - 结构化输出以 JSON envelope 为准。
99
+ - 更新提示字段统一为:`_notice`
100
+ - 所有有副作用的命令必须支持:`--dry-run`
101
+ - 支持:`--jq`
102
+ - exit code 与错误码统一收敛到 v2 新协议。
103
+
104
+ ### 2.5 环境变量冻结
105
+
106
+ 存在一个已发现冲突:
107
+
108
+ - v2 命令文档当前使用 `AVIKI_*`
109
+ - v1 Python CLI 当前使用 `AWIKI_*`
110
+ - 旧环境还有 `E2E_*`
111
+
112
+ 实现规划采用以下冻结规则:
113
+
114
+ - **v2 新变量 canonical 名称使用 `AVIKI_*`**(遵循当前 v2 命令文档)
115
+ - **兼容读取旧变量**:`AWIKI_*` 与 `E2E_*`
116
+ - doctor 需要显式提示当前命中的来源与优先级,避免隐式混用
117
+
118
+ ### 2.6 参考基线冻结
119
+
120
+ - **SQLite 表设计以 `../awiki-agent-id-message/scripts/local_store.py` 与 `../awiki-agent-id-message/references/local-store-schema.md` 为基线参考。**
121
+ - **凭证文件设计以 `../awiki-agent-id-message/scripts/credential_layout.py` 与 `../awiki-agent-id-message/scripts/credential_store.py` 为基线参考。**
122
+ - 首版实现优先保证“稳定迁移”和“兼容导入”,不主动重构这些数据模型。
123
+
124
+ ### 2.7 已知审计项
125
+
126
+ 这些问题不阻塞规划,但必须在 Phase 0 记录为审计任务:
127
+
128
+ 1. `local-store-schema.md` 当前未列出 `e2ee_outbox`,但 `local_store.py` 中该表是权威存在的。
129
+ 2. v2 文档使用 `AVIKI_*`,v1 实际环境使用 `AWIKI_*`,需要在实现层做兼容。
130
+ 3. E2EE 协议文档存在历史冲突,v2 必须先冻结具体协议再编码实现。
131
+
132
+ ---
133
+
134
+ ## 3. 目标工程结构
135
+
136
+ 建议把本仓库直接落成单仓 Go CLI,目录结构如下:
137
+
138
+ ```text
139
+ .
140
+ ├── cmd/
141
+ │ └── awiki-cli/
142
+ ├── internal/
143
+ │ ├── app/
144
+ │ ├── cli/
145
+ │ ├── cmdmeta/
146
+ │ ├── config/
147
+ │ ├── output/
148
+ │ ├── schema/
149
+ │ ├── doctor/
150
+ │ ├── identity/
151
+ │ ├── messaging/
152
+ │ ├── group/
153
+ │ ├── people/
154
+ │ ├── page/
155
+ │ ├── runtime/
156
+ │ ├── transport/
157
+ │ │ ├── http/
158
+ │ │ ├── websocket/
159
+ │ │ └── ipc/
160
+ │ ├── secure/
161
+ │ ├── store/
162
+ │ ├── serviceapi/
163
+ │ ├── migrate/
164
+ │ └── buildinfo/
165
+ ├── schemas/
166
+ ├── skills/
167
+ │ ├── awiki-shared/
168
+ │ ├── awiki-id/
169
+ │ ├── awiki-msg/
170
+ │ ├── awiki-runtime/
171
+ │ ├── awiki-people/
172
+ │ ├── awiki-page/
173
+ │ └── awiki-debug/
174
+ ├── docs/
175
+ │ ├── architecture/
176
+ │ └── plan/
177
+ ├── testdata/
178
+ │ ├── credentials/
179
+ │ ├── sqlite/
180
+ │ ├── rpc/
181
+ │ └── golden/
182
+ └── .goreleaser.yaml
183
+ ```
184
+
185
+ ### 3.1 模块职责
186
+
187
+ | 模块 | 职责 |
188
+ |---|---|
189
+ | `internal/cli` | Cobra 命令树、flag 绑定、命令执行入口 |
190
+ | `internal/cmdmeta` | 命令元数据、schema/help/docs 生成的单一事实来源 |
191
+ | `internal/output` | JSON envelope、pretty/table/ndjson、错误输出、_notice |
192
+ | `internal/config` | XDG 路径、env 兼容、配置加载、默认 identity 选择 |
193
+ | `internal/identity` | DID、注册、绑定、恢复、profile、多 identity 管理 |
194
+ | `internal/messaging` | direct/group 消息收发、history、mark-read |
195
+ | `internal/group` | group 生命周期与本地快照管理 |
196
+ | `internal/secure` | E2EE session、secure send、outbox、repair/retry/drop |
197
+ | `internal/runtime` | mode、listener、heartbeat、service lifecycle |
198
+ | `internal/transport/*` | HTTP、WSS、IPC 抽象与实现 |
199
+ | `internal/store` | SQLite DAO、migrations、identity store、runtime state |
200
+ | `internal/serviceapi` | user-service / message-service 客户端与请求映射 |
201
+ | `internal/migrate` | 从 v1 导入 credentials / SQLite / runtime state |
202
+
203
+ ---
204
+
205
+ ## 4. 参考基线:SQLite 与凭证文件
206
+
207
+ 这是本规划里必须明确记录的项目约束。
208
+
209
+ ### 4.1 凭证文件设计基线
210
+
211
+ v2 的 identity 存储设计,参考以下实现:
212
+
213
+ - `../awiki-agent-id-message/scripts/credential_layout.py`
214
+ - `../awiki-agent-id-message/scripts/credential_store.py`
215
+ - `../awiki-agent-id-message/scripts/credential_migration.py`
216
+
217
+ #### 4.1.1 目录布局基线
218
+
219
+ v2 采用 XDG 目录,但 identity 内部文件布局继续参考 v1 的 indexed multi-credential layout:
220
+
221
+ ```text
222
+ ~/.config/awiki-cli/config.yaml
223
+ ~/.config/awiki-cli/identities/index.json
224
+ ~/.config/awiki-cli/identities/<identity-dir>/identity.json
225
+ ~/.config/awiki-cli/identities/<identity-dir>/auth.json
226
+ ~/.config/awiki-cli/identities/<identity-dir>/did_document.json
227
+ ~/.config/awiki-cli/identities/<identity-dir>/key-1-private.pem
228
+ ~/.config/awiki-cli/identities/<identity-dir>/key-1-public.pem
229
+ ~/.config/awiki-cli/identities/<identity-dir>/e2ee-signing-private.pem
230
+ ~/.config/awiki-cli/identities/<identity-dir>/e2ee-agreement-private.pem
231
+ ~/.config/awiki-cli/identities/<identity-dir>/e2ee-state.json
232
+ ```
233
+
234
+ #### 4.1.2 index.json 基线
235
+
236
+ 首版实现遵循以下约束:
237
+
238
+ - `schema_version` 与 v1 索引版本兼容读取
239
+ - `default_identity_name` 语义等价于 v1 的 `default_credential_name`
240
+ - index 中保存 identity 元信息,不保存私钥原文
241
+ - `default` 作为 alias 时优先解析显式 `default`,再 fallback 到当前默认 identity
242
+
243
+ #### 4.1.3 文件权限基线
244
+
245
+ - identity 目录:`0700`
246
+ - 私钥 / token / json 凭证:`0600`
247
+ - 文档与日志中不得打印私钥、JWT、E2EE 私钥
248
+
249
+ #### 4.1.4 迁移基线
250
+
251
+ 需要兼容识别 v1 flat legacy layout:
252
+
253
+ - `<credential>.json`
254
+ - `e2ee_<credential>.json`
255
+ - `<credential>_did_document.json`
256
+ - `<credential>_private_key.pem`
257
+
258
+ 并提供统一入口:
259
+
260
+ ```bash
261
+ awiki-cli migrate from-v1
262
+ ```
263
+
264
+ ### 4.2 SQLite 表设计基线
265
+
266
+ v2 本地 SQLite 设计参考以下来源:
267
+
268
+ - `../awiki-agent-id-message/scripts/local_store.py`
269
+ - `../awiki-agent-id-message/references/local-store-schema.md`
270
+ - `../awiki-agent-id-message/scripts/database_migration.py`
271
+ - `../awiki-agent-id-message/scripts/e2ee_session_store.py`
272
+ - `../awiki-agent-id-message/scripts/e2ee_outbox.py`
273
+
274
+ #### 4.2.1 首版必须保留的表
275
+
276
+ | 表名 | 用途 | 基线来源 |
277
+ |---|---|---|
278
+ | `contacts` | 联系人、沉淀关系、follow-up 信息 | `local_store.py` / `local-store-schema.md` |
279
+ | `messages` | direct/group 收发消息本地缓存 | `local_store.py` / `local-store-schema.md` |
280
+ | `e2ee_outbox` | secure 失败重试 / drop / resend | `local_store.py` / `e2ee_outbox.py` |
281
+ | `groups` | group 快照、本地 membership 状态 | `local_store.py` / `local-store-schema.md` |
282
+ | `group_members` | group 成员快照 | `local_store.py` / `local-store-schema.md` |
283
+ | `relationship_events` | 关系沉淀事件流 | `local_store.py` / `local-store-schema.md` |
284
+ | `e2ee_sessions` | 私聊 E2EE session 持久化 | `local_store.py` / `e2ee_session_store.py` |
285
+
286
+ #### 4.2.2 首版必须保留的视图
287
+
288
+ | 视图 | 用途 |
289
+ |---|---|
290
+ | `threads` | 聚合线程摘要 |
291
+ | `inbox` | 所有 incoming message 视图 |
292
+ | `outbox` | 所有 outgoing message 视图 |
293
+
294
+ #### 4.2.3 首版必须保留的关键设计原则
295
+
296
+ - 本地快照隔离维度必须继续使用 `owner_did`
297
+ - `credential_name` / `identity_name` 字段继续保留,用于诊断、迁移与兼容
298
+ - thread id 规则保持对称:
299
+ - 私聊:`dm:{min_did}:{max_did}`
300
+ - 群聊:`group:{group_id}`
301
+ - schema version 继续使用 `PRAGMA user_version`
302
+ - 首版 migration 优先保证与 v1 数据可导入,不主动做大规模重构
303
+
304
+ #### 4.2.4 规划中的文档补齐任务
305
+
306
+ 需要在后续实现中补齐以下差异:
307
+
308
+ - `local-store-schema.md` 需补充 `e2ee_outbox` 的正式表说明,避免文档与实现脱节
309
+
310
+ ---
311
+
312
+ ## 5. 外部接口与命令映射基线
313
+
314
+ ### 5.1 user-service 相关命令映射
315
+
316
+ | CLI 命令 | 服务/API 文档 | 说明 |
317
+ |---|---|---|
318
+ | `id create` | `../user-service/docs/api/did-auth.md`(仅 bootstrap 背景) | 本地 DID 材料生成;不是对外用户完成态 |
319
+ | `id register` | `../user-service/docs/api/did-auth.md` + `authentication.md` + `handle.md` | 创建远端 user、注册 handle、写回凭证 |
320
+ | `id bind` | `../user-service/docs/api/authentication.md` | 手机/邮箱绑定 |
321
+ | `id resolve` | `../user-service/docs/api/did-profile.md` + `handle.md` + `users.md` | DID/Handle 解析与用户摘要查询 |
322
+ | `id recover` | `../user-service/docs/api/did-auth.md` + `handle.md` | 通过手机验证码恢复 handle DID 绑定 |
323
+ | `id profile get/set` | `../user-service/docs/api/profile.md` + `did-profile.md` + `users.md` | 自己/公开 profile 与当前用户查询 |
324
+ | `people follow/unfollow/status` | `../user-service/docs/api/relationships.md` | follow/unfollow/status |
325
+ | `group *` 生命周期 | `../user-service/docs/api/group.md` | create/get/update/join/leave/kick/list members 等 |
326
+
327
+ ### 5.2 message-service 相关命令映射
328
+
329
+ | CLI 命令 | 服务/API 文档 | 说明 |
330
+ |---|---|---|
331
+ | `msg send --to` | `../message-service/docs/api/ANP-client-server-api-direct.md` | `direct.send` |
332
+ | `msg send --group` | `../message-service/docs/api/ANP-client-server-api-group.md` | `group.send` |
333
+ | `msg inbox` | `ANP-client-server-api-direct.md` | `inbox.get` local-view 方法 |
334
+ | `msg mark-read` | `ANP-client-server-api-direct.md` | `inbox.mark_read` |
335
+ | `msg history --with` | `ANP-client-server-api-direct.md` | `direct.get_history` |
336
+ | `group messages` | `ANP-client-server-api-group.md` | `group.list_messages` |
337
+ | `msg secure *` | `ANP-client-server-api-direct.md` | prekey/session/init/ack/e2ee_msg |
338
+ | 附件增强 | `ANP-client-server-api-attachment.md` | `attachment.create_slot` / `commit_object` / download ticket |
339
+
340
+ ### 5.3 飞书 CLI 中需要借鉴的部分
341
+
342
+ `../cli/` 只作为产品结构和工程组织参考,不直接复制业务体量。需要借鉴的点包括:
343
+
344
+ 1. `cmd/root.go` 的 Cobra 根命令组织方式
345
+ 2. `schema` / `doctor` / `completion` 作为一级产品命令
346
+ 3. `internal/output` 式的统一输出与错误 envelope
347
+ 4. `shortcuts` 与 domain service commands 分离
348
+ 5. `skills/lark-shared` + domain skill 的分层方式
349
+ 6. update notice 的 `_notice` 注入策略
350
+ 7. GoReleaser + GitHub Releases + npm wrapper 的发布链路
351
+
352
+ ---
353
+
354
+ ## 6. 分阶段实施计划
355
+
356
+ 本节是本规划的核心。每个阶段都以“可交付物”和“验收标准”为中心,而不是只写方向。
357
+
358
+ ### Phase 0:冻结与审计
359
+
360
+ **目标**:把会影响后续所有实现的契约问题全部冻结。
361
+
362
+ **主要任务**:
363
+
364
+ 1. 把最终命令树、全局 flags、输出 envelope、错误码写成一份实现约束表。
365
+ 2. 对照 `awiki-command-v2.md` 与 `awiki-v2-architecture.md`,标出所有实现需要遵守的冻结项。
366
+ 3. 完成三类差异审计:
367
+ - v2 文档内部冲突
368
+ - v2 文档与 v1 Python 行为差异
369
+ - v2 文档与 API 文档差异
370
+ 4. 明确 E2EE 协议冻结结果。
371
+ 5. 明确环境变量兼容顺序与 XDG 目录规则。
372
+
373
+ **交付物**:
374
+
375
+ - 一份实现约束表(可并入本规划附录)
376
+ - 一份 API/命令/脚本能力对照表
377
+ - 一份风险清单与 ADR 列表
378
+
379
+ **验收标准**:
380
+
381
+ - 后续阶段不再允许更改主命令树与主输出协议
382
+ - 后续阶段不再允许更改 identity/credential 命名策略
383
+ - 已列出所有阻塞实现的协议冲突项并给出裁决
384
+
385
+ ### Phase 1:CLI 产品壳
386
+
387
+ **目标**:搭起可运行的 v2 CLI 外壳,先稳定产品面,再做业务实现。
388
+
389
+ **主要任务**:
390
+
391
+ 1. 初始化 Go 模块与 `cobra` 根命令。
392
+ 2. 建立顶级命令骨架:
393
+ - `status`
394
+ - `docs`
395
+ - `schema`
396
+ - `doctor`
397
+ - `version`
398
+ - `completion`
399
+ - `config`
400
+ - `id`
401
+ - `msg`
402
+ - `group`
403
+ - `runtime`
404
+ - `people`
405
+ - `page`
406
+ - `debug`
407
+ 3. 建立全局 flags:
408
+ - `--format`
409
+ - `--jq`
410
+ - `--dry-run`
411
+ - `--identity`
412
+ - `--verbose`
413
+ 4. 实现统一 JSON success/error envelope。
414
+ 5. 实现 update notice 注入 `_notice`。
415
+ 6. 实现 `schema` 基础框架,哪怕最开始只输出静态元数据。
416
+ 7. 实现 `doctor` 基础检查框架,先检查路径、配置、identity store、SQLite 可达性。
417
+
418
+ **交付物**:
419
+
420
+ - 可编译的 `awiki-cli`
421
+ - 完整 help 树
422
+ - 统一输出层
423
+ - schema/doctor 基础命令
424
+
425
+ **验收标准**:
426
+
427
+ - `awiki-cli --help` 展示最终顶级命令树
428
+ - `awiki-cli schema` 能输出结构化命令元数据
429
+ - `awiki-cli doctor` 能输出基础诊断结果
430
+ - 所有命令在失败时都遵循统一错误 envelope
431
+
432
+ ### Phase 2:配置、Identity 与凭证存储
433
+
434
+ **目标**:先落地本地 identity 基础设施,为后续 User 完成态做准备。
435
+
436
+ **主要任务**:
437
+
438
+ 1. 落地 XDG 目录解析:
439
+ - config
440
+ - data
441
+ - state
442
+ - cache
443
+ 2. 落地 env 兼容读取:
444
+ - `AVIKI_*`
445
+ - fallback `AWIKI_*`
446
+ - fallback `E2E_*`
447
+ 3. 实现 identity index store。
448
+ 4. 实现 identity create/list/use/current。
449
+ 5. 明确 `id create` 只负责本地 DID / 密钥 / did_document 生成,不作为对外用户完成态。
450
+ 6. 完成 v1 credential import。
451
+ 7. 完成旧 flat legacy credential 扫描与导入提示。
452
+ 8. 设计 token / daemon token 与 keychain 的接口层,但首版可先用受权限保护的文件存储。
453
+
454
+ **交付物**:
455
+
456
+ - identity store
457
+ - v2 index.json + per-identity dir
458
+ - 本地 bootstrap 命令
459
+ - migrate from-v1(credential 部分)
460
+
461
+ **验收标准**:
462
+
463
+ - `id create/list/use/current` 可用
464
+ - 旧 `.credentials` 能被识别、提示、导入
465
+ - 文件权限符合最小权限要求
466
+
467
+ ### Phase 3:User、Handle 与 Credential 完整化
468
+
469
+ **目标**:跑通“可用用户态”主链路:创建远端 user、注册 handle、绑定联系方式、记录本地凭证。
470
+
471
+ > 说明:旧版本规划把这部分隐含在 identity 阶段里,导致“本地 DID bootstrap”和“远端 user 完成态”混在一起。本阶段将两者显式拆开,并冻结 handle-first 约束。
472
+
473
+ **主要任务**:
474
+
475
+ 1. 明确主流程为 handle-first:
476
+ - `id register` 是 canonical 用户创建入口
477
+ - `handle` 为必填
478
+ - 不支持 pure DID 作为对外用户完成态
479
+ 2. 对接 user-service API:
480
+ - `POST /did-auth/rpc` `register`
481
+ - `POST /handle/rpc` `send_otp`
482
+ - `POST /did-auth/rpc` `recover_handle`
483
+ - `POST /auth/phone-bind-send`
484
+ - `POST /auth/phone-bind-verify`
485
+ - `POST /auth/email-send`
486
+ - `GET /auth/email-status`
487
+ - `POST /did/profile/rpc` `get_me` / `update_me` / `get_public_profile`
488
+ - `POST /users/rpc` `get_me` / `get_by_did` / `get_by_handle`
489
+ 3. 参考 Python 版本补齐非交互 CLI 流程:
490
+ - `register_handle.py`
491
+ - `bind_contact.py`
492
+ - `recover_handle.py`
493
+ - `get_profile.py`
494
+ - `update_profile.py`
495
+ - `credential_store.py`
496
+ 4. 本地凭证落盘与索引补齐:
497
+ - `identity.json` 内部记录 `did / user_id / handle / created_at`
498
+ - `auth.json` 记录 token
499
+ - `did_document.json` 记录当前 DID 文档
500
+ - index 中内部同步 `user_id`、`handle` 与默认 identity 解析
501
+ - `user_id` 只作为内部映射字段保存,不进入公共 CLI 输出
502
+ 5. 建立当前 identity 的“用户完成态”判断:
503
+ - local-only identity
504
+ - registered user
505
+ - partial user / incomplete user
506
+ 6. 对 `doctor`、`msg`、`runtime listener` 增加 gating:
507
+ - 未完成 handle 注册的 identity 不能进入消息和 realtime 主链路
508
+ - CLI 需要明确提示先完成 `id register` 或 `id recover`
509
+
510
+ **交付物**:
511
+
512
+ - handle-backed user lifecycle 命令
513
+ - OTP / email verification / bind / recover 流程
514
+ - 完整 credential 持久化
515
+ - 用户完成态检查与 gating
516
+
517
+ **验收标准**:
518
+
519
+ - `id register` 能完成:
520
+ - 创建远端 user
521
+ - 创建或恢复 handle
522
+ - 保存本地凭证
523
+ - 形成可复用 identity
524
+ - `id bind`、`id recover`、`id profile get/set` 能与 user-service 跑通
525
+ - `id current` 与 `doctor` 能识别 local-only identity 与 registered user
526
+ - 未完成 handle 注册的 identity 不能直接执行 `msg *` 与 `runtime listener *`
527
+
528
+ ### Phase 4:SQLite 本地状态与迁移
529
+
530
+ **目标**:把 v1 的本地状态模型迁到 v2,同时保留 owner_did 隔离和 v1 可导入能力。
531
+
532
+ **主要任务**:
533
+
534
+ 1. 建立 SQLite 连接层、WAL 模式、schema version 管理。
535
+ 2. 落地首版表:
536
+ - `contacts`
537
+ - `messages`
538
+ - `e2ee_outbox`
539
+ - `groups`
540
+ - `group_members`
541
+ - `relationship_events`
542
+ - `e2ee_sessions`
543
+ 3. 落地首版视图:
544
+ - `threads`
545
+ - `inbox`
546
+ - `outbox`
547
+ 4. 建立 DAO 层与查询接口。
548
+ 5. 建立从 v1 SQLite 导入的 migration。
549
+ 6. 支持 DID 恢复后的 owner rebind。
550
+ 7. 建立 test fixtures:
551
+ - v1 DB 样本
552
+ - 多 identity 样本
553
+ - 含 secure outbox / group / relationship 的样本
554
+
555
+ **交付物**:
556
+
557
+ - SQLite schema
558
+ - migration runner
559
+ - DAO 层
560
+ - v1 DB 导入能力
561
+
562
+ **验收标准**:
563
+
564
+ - 本地 SQLite 可初始化、升级、查询
565
+ - v1 DB 可导入到 v2 schema
566
+ - owner_did 隔离语义不丢失
567
+ - `threads/inbox/outbox` 查询结果符合预期
568
+
569
+ ### Phase 5:Messaging 与 Group 基础域
570
+
571
+ **目标**:先跑通 plain direct / plain group 的主链路。
572
+
573
+ **主要任务**:
574
+
575
+ 1. 实现 message-service 客户端:
576
+ - `direct.send`
577
+ - `inbox.get`
578
+ - `inbox.mark_read`
579
+ - `direct.get_history`
580
+ 2. 实现 user-service group 客户端:
581
+ - `create`
582
+ - `get`
583
+ - `update`
584
+ - `refresh_join_code`
585
+ - `get_join_code`
586
+ - `set_join_enabled`
587
+ - `join`
588
+ - `leave`
589
+ - `kick_member`
590
+ - `list_members`
591
+ - `post_message`
592
+ - `list_messages`
593
+ 3. 落地 CLI 命令:
594
+ - `msg send`
595
+ - `msg inbox`
596
+ - `msg history`
597
+ - `msg mark-read`
598
+ - `group create/show/update/join/leave/kick/members/messages/code*`
599
+ 4. 本地消息与群组快照持久化。
600
+ 5. group 命令与消息命令的边界收敛:
601
+ - 群生命周期在 `group`
602
+ - 群发消息仍从 `msg send --group` 进入
603
+ 6. 把 Phase 3 的 user gating 作为消息主链路前置条件,默认拒绝 local-only identity。
604
+
605
+ **交付物**:
606
+
607
+ - plain direct/group 全链路
608
+ - 本地缓存与历史
609
+ - group 本地快照
610
+
611
+ **验收标准**:
612
+
613
+ - 可以完成 direct 发消息、收件箱、历史、标记已读
614
+ - 可以完成 group 创建、入群、看成员、看消息、更新、离开、踢人
615
+ - 相关数据能稳定写入 SQLite
616
+
617
+ ### Phase 6:Secure / E2EE 域
618
+
619
+ **目标**:补齐 awiki 的 secure messaging 差异化能力。
620
+
621
+ **主要任务**:
622
+
623
+ 1. 根据冻结后的协议实现 secure session store。
624
+ 2. 完成以下命令:
625
+ - `msg secure status`
626
+ - `msg secure init`
627
+ - `msg secure repair`
628
+ - `msg secure failed`
629
+ - `msg secure retry`
630
+ - `msg secure drop`
631
+ 3. 保留 v1 的关键行为:
632
+ - auto-init
633
+ - inbox auto-processing
634
+ - session persistence
635
+ - outbox resend/drop
636
+ - peer failure feedback
637
+ 4. 将 secure 状态与本地消息表、本地 outbox 表关联。
638
+ 5. 处理 listener 与 secure auto-processing 的边界。
639
+
640
+ **交付物**:
641
+
642
+ - secure 命令面
643
+ - session store
644
+ - outbox retry/drop 机制
645
+ - E2EE 收发主路径
646
+
647
+ **验收标准**:
648
+
649
+ - direct E2EE 可以建立 session、发送、处理 incoming、重试失败项
650
+ - secure 状态能通过 CLI 与 doctor 观察
651
+ - secure 失败不会污染 plain message 主路径
652
+
653
+ > 默认假设:group E2EE 不作为首发阻塞项,待 direct E2EE 稳定后再进入后续里程碑。
654
+
655
+ ### Phase 7:Runtime、Listener、Heartbeat 与 IPC
656
+
657
+ **目标**:把 v1 的 realtime/runtime 机制收敛成 v2 独立 runtime 域。
658
+
659
+ **主要任务**:
660
+
661
+ 1. 实现 runtime mode:
662
+ - `http`
663
+ - `websocket`
664
+ 2. websocket 模式下实现:
665
+ - listener 持有唯一远端连接
666
+ - 本地 IPC / daemon 转发 CLI RPC
667
+ - 后台服务 install/start/stop/restart/status
668
+ 3. http 模式下实现:
669
+ - 业务命令直接走服务端 RPC
670
+ - listener 可选关闭
671
+ 4. 实现 heartbeat 任务。
672
+ 5. 实现 runtime setup/status/doctor 深度检查。
673
+ 6. 兼容导入 v1 listener/settings 相关配置。
674
+ 7. listener 启动前校验当前 identity 已完成 User 阶段,拒绝 local-only identity。
675
+
676
+ **交付物**:
677
+
678
+ - runtime mode 管理
679
+ - listener 服务管理
680
+ - IPC / local daemon
681
+ - heartbeat
682
+
683
+ **验收标准**:
684
+
685
+ - `runtime status/setup/mode/listener/heartbeat` 命令可用
686
+ - websocket 模式下所有消息命令能通过本地 daemon 工作
687
+ - http 模式下无需 listener 也可执行业务命令
688
+ - doctor 能报告 runtime 当前状态和异常原因
689
+
690
+ ### Phase 8:扩展域、skills、docs、schema 生成
691
+
692
+ **目标**:建立“命令元数据驱动产品文档”的闭环。
693
+
694
+ **主要任务**:
695
+
696
+ 1. 实现扩展域:
697
+ - `people`
698
+ - `page`
699
+ - `debug`
700
+ - `discovery`(如果保留在扩展域)
701
+ 2. 构建 `cmdmeta` 元数据层,作为以下输出的单一事实来源:
702
+ - CLI help
703
+ - `schema`
704
+ - `docs` 生成
705
+ - skills 命令引用
706
+ 3. 拆分 skills:
707
+ - `awiki-shared`
708
+ - `awiki-id`
709
+ - `awiki-msg`
710
+ - `awiki-runtime`
711
+ - `awiki-people`
712
+ - `awiki-page`
713
+ - `awiki-debug`
714
+ 4. 建立 docs / schema / skills 引用校验。
715
+ 5. 生成:
716
+ - `schemas/cli.json`
717
+ - `schemas/commands/*.json`
718
+ - shell completion
719
+ - man page
720
+
721
+ **交付物**:
722
+
723
+ - 扩展域命令
724
+ - skills 分层目录
725
+ - schema/docs/help 生成链路
726
+
727
+ **验收标准**:
728
+
729
+ - 命令帮助、schema、docs、skills 不再相互漂移
730
+ - 新增命令只需要更新一处元数据即可生成多处产物
731
+ - AI 不依赖外部 skill 也能理解核心 CLI 行为
732
+
733
+ ### Phase 9:发布、切换与收尾
734
+
735
+ **目标**:把 v2 从“开发完成”转成“可发布、可切换、可回滚”的产品。
736
+
737
+ **主要任务**:
738
+
739
+ 1. 接入 GoReleaser。
740
+ 2. 产出多平台二进制与 checksums。
741
+ 3. 可选接入 npm wrapper。
742
+ 4. 生成安装说明、升级说明、迁移指南。
743
+ 5. 落地 `migrate from-v1` 的完整入口。
744
+ 6. 建立 shadow / verify / cutover 策略:
745
+ - 影子校验
746
+ - 双跑对比
747
+ - 切默认
748
+ - 回滚策略
749
+
750
+ **交付物**:
751
+
752
+ - release pipeline
753
+ - migration guide
754
+ - cutover checklist
755
+
756
+ **验收标准**:
757
+
758
+ - release 可生成 macOS / Linux / Windows 包
759
+ - 用户可从 v1 导入 credentials 和 SQLite 数据
760
+ - 文档明确说明切换、回滚和兼容边界
761
+
762
+ ---
763
+
764
+ ## 7. 里程碑与建议拆包
765
+
766
+ 为了便于拆成 Epic/Issue,建议按下列工作包推进。
767
+
768
+ | 编号 | 工作包 | 对应阶段 | 完成定义 |
769
+ |---|---|---|---|
770
+ | EPIC-01 | 命令壳与输出协议 | Phase 0-1 | 根命令、输出 envelope、schema/doctor 骨架完成 |
771
+ | EPIC-02 | 配置与路径体系 | Phase 2 | XDG、env 兼容、default identity 解析完成 |
772
+ | EPIC-03 | identity store 与迁移 | Phase 2 | index.json、identity dir、v1 credential import 完成 |
773
+ | EPIC-04 | user + handle lifecycle | Phase 3 | register/bind/recover/profile/current + user gating 完成 |
774
+ | EPIC-05 | SQLite schema 与 DAO | Phase 4 | 表/视图/migration/fixtures 完成 |
775
+ | EPIC-06 | direct messaging | Phase 5 | send/inbox/history/mark-read 全链路完成 |
776
+ | EPIC-07 | group lifecycle | Phase 5 | create/join/show/members/messages/update/leave/kick 完成 |
777
+ | EPIC-08 | secure direct messaging | Phase 6 | session/outbox/retry/drop/auto-process 完成 |
778
+ | EPIC-09 | runtime 与 listener | Phase 7 | http/websocket、listener、IPC、heartbeat 完成 |
779
+ | EPIC-10 | docs/schema/skills 生成 | Phase 8 | cmdmeta 驱动链路闭环完成 |
780
+ | EPIC-11 | 发布与切换 | Phase 9 | goreleaser、迁移指南、cutover checklist 完成 |
781
+
782
+ ---
783
+
784
+ ## 8. 测试计划
785
+
786
+ ### 8.1 单元测试
787
+
788
+ 覆盖:
789
+
790
+ - config merge 与 env fallback
791
+ - identity index 解析与默认 identity 选择
792
+ - local-only identity vs registered user 状态判断
793
+ - output envelope / error mapping / exit code
794
+ - schema 生成与 help 生成
795
+ - thread id 生成
796
+ - SQLite DAO 与 view 查询
797
+ - secure session / outbox 状态机
798
+
799
+ ### 8.2 迁移测试
800
+
801
+ 覆盖:
802
+
803
+ - 从 `../awiki-agent-id-message/.credentials/` 样本导入
804
+ - 从 v1 SQLite 样本导入
805
+ - legacy flat file 检测与修复
806
+ - owner_did rebind
807
+ - secure session / outbox 导入
808
+
809
+ ### 8.3 API 集成测试
810
+
811
+ 覆盖:
812
+
813
+ - `authentication.md`
814
+ - `did-auth.md`
815
+ - `handle.md`
816
+ - `profile.md`
817
+ - `did-profile.md`
818
+ - `users.md`
819
+ - `relationships.md`
820
+ - `group.md`
821
+ - `ANP-client-server-api-direct.md`
822
+ - `ANP-client-server-api-group.md`
823
+ - `ANP-client-server-api-attachment.md`(若首版纳入附件)
824
+
825
+ ### 8.4 runtime 测试
826
+
827
+ 覆盖:
828
+
829
+ - http mode
830
+ - websocket mode
831
+ - listener install/start/stop/status
832
+ - 本地 IPC / daemon
833
+ - heartbeat run/status
834
+ - runtime doctor 检查
835
+
836
+ ### 8.5 系统测试
837
+
838
+ 建议通过同级服务仓完成端到端联调,主链路至少覆盖:
839
+
840
+ 1. `id create`(仅验证本地 bootstrap)
841
+ 2. `id register --handle ...`
842
+ 3. `id bind`
843
+ 4. `id current` / `doctor`
844
+ 5. `msg send --to`
845
+ 6. `msg inbox`
846
+ 7. `msg history`
847
+ 8. `group create` / `join` / `members` / `messages`
848
+ 9. `msg secure init` / `msg secure retry`
849
+ 10. `runtime mode set websocket` + listener
850
+
851
+ ### 8.6 文档与生成校验
852
+
853
+ 覆盖:
854
+
855
+ - 每个命令都有 schema
856
+ - 每个命令 help 可生成
857
+ - skills 中引用的命令必须存在
858
+ - docs / schema / help / generated reference 不允许漂移
859
+
860
+ ---
861
+
862
+ ## 9. 最终验收标准
863
+
864
+ 以下条件全部满足时,才认为 v2 首版达到“可发布”标准:
865
+
866
+ 1. 所有核心能力都通过 `awiki-cli` 统一入口暴露。
867
+ 2. `id / msg / group / runtime` 的主链路可实际执行,不仅有命令壳。
868
+ 3. handle-backed user 阶段是显式能力:可以区分 local-only identity 与 registered user。
869
+ 4. `msg` 与 `runtime listener` 默认拒绝未完成 handle 注册的 identity。
870
+ 5. `schema`、`doctor`、`docs` 是 CLI 本体能力,而不是外部补丁。
871
+ 6. 所有副作用命令支持 `--dry-run`。
872
+ 7. 所有命令遵循统一输出协议和错误协议。
873
+ 8. direct plain、group plain、direct secure 三条主路径可用。
874
+ 9. websocket runtime + listener + IPC 可用。
875
+ 10. SQLite 本地状态可创建、升级、迁移、诊断。
876
+ 11. 凭证目录布局支持 v2 新格式,并兼容从 v1 导入。
877
+ 12. docs / schema / skills / help 由统一元数据驱动,避免文档漂移。
878
+ 13. 发布链路可生成多平台包,并有明确迁移与回滚说明。
879
+
880
+ ---
881
+
882
+ ## 10. 默认实现假设
883
+
884
+ 除非后续明确调整,本规划默认采用以下实现假设:
885
+
886
+ 1. 首版语言固定为 Go。
887
+ 2. CLI 框架固定为 Cobra。
888
+ 3. 首版采用 handle-first 用户流程;handle 为必填,不支持 pure DID 作为对外用户完成态。
889
+ 4. `id create` 仅作为本地 bootstrap / 迁移辅助能力,不作为 `msg`、`group`、`runtime listener` 的前置完成态。
890
+ 5. 首版优先实现 direct E2EE,不把 group E2EE 作为首发阻塞项。
891
+ 6. 首版不强制接入系统 keychain,可先采用受权限保护的文件存储;但接口层需要预留 keychain 扩展点。
892
+ 7. 首版必须兼容导入 `../awiki-agent-id-message/` 的凭证与 SQLite 数据。
893
+ 8. 首版不追求覆盖 v1 所有边角脚本,而是先覆盖架构文档定义的 canonical 命令面。
894
+ 9. 首版发布主渠道为 GitHub Releases;npm wrapper 为可选增强项。
895
+ 10. Go 核心实现固定使用 Go 1.22,并保持 pure Go,禁止依赖 CGO;如果后续需要做系统兼容性壳层,可放在 TypeScript/Node 的薄壳中实现。
896
+
897
+ ---
898
+
899
+ ## 11. 本文档维护规则
900
+
901
+ - 当 `docs/architecture/awiki-v2-architecture.md` 或 `docs/architecture/awiki-command-v2.md` 发生影响实施范围的变化时,必须同步更新本文档。
902
+ - 当 v1 SQLite schema 或凭证布局的参考基线发生变化时,需要同步更新“参考基线”章节。
903
+ - 当新增一级命令或调整 canonical contract 时,必须同步更新 Phase、工作包、验收标准与测试计划。