opencode-wiki-historian 0.2.0

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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +381 -0
  3. package/dist/chronology.d.ts +36 -0
  4. package/dist/chronology.js +67 -0
  5. package/dist/config.d.ts +112 -0
  6. package/dist/config.js +158 -0
  7. package/dist/index.d.ts +31 -0
  8. package/dist/index.js +136 -0
  9. package/dist/jsonc.d.ts +17 -0
  10. package/dist/jsonc.js +131 -0
  11. package/dist/map.d.ts +58 -0
  12. package/dist/map.js +196 -0
  13. package/dist/migrate-apply.d.ts +40 -0
  14. package/dist/migrate-apply.js +144 -0
  15. package/dist/migrate-score.d.ts +29 -0
  16. package/dist/migrate-score.js +267 -0
  17. package/dist/migrate-store.d.ts +52 -0
  18. package/dist/migrate-store.js +77 -0
  19. package/dist/migrate.d.ts +65 -0
  20. package/dist/migrate.js +111 -0
  21. package/dist/templates/genres.d.ts +65 -0
  22. package/dist/templates/genres.js +228 -0
  23. package/dist/templates/skeletons.d.ts +48 -0
  24. package/dist/templates/skeletons.js +558 -0
  25. package/dist/tools/create.d.ts +9 -0
  26. package/dist/tools/create.js +77 -0
  27. package/dist/tools/local.d.ts +10 -0
  28. package/dist/tools/local.js +107 -0
  29. package/dist/tools/mutate.d.ts +11 -0
  30. package/dist/tools/mutate.js +157 -0
  31. package/dist/tools/read.d.ts +9 -0
  32. package/dist/tools/read.js +104 -0
  33. package/dist/tools/shared.d.ts +52 -0
  34. package/dist/tools/shared.js +87 -0
  35. package/dist/tools/write.d.ts +10 -0
  36. package/dist/tools/write.js +148 -0
  37. package/dist/tools.d.ts +23 -0
  38. package/dist/tools.js +43 -0
  39. package/dist/translate.d.ts +44 -0
  40. package/dist/translate.js +207 -0
  41. package/dist/wiki/assets.d.ts +42 -0
  42. package/dist/wiki/assets.js +91 -0
  43. package/dist/wiki/client.d.ts +67 -0
  44. package/dist/wiki/client.js +221 -0
  45. package/dist/wiki/locale.d.ts +66 -0
  46. package/dist/wiki/locale.js +154 -0
  47. package/dist/wiki/pages.d.ts +7 -0
  48. package/dist/wiki/pages.js +7 -0
  49. package/dist/wiki/pages.read.d.ts +114 -0
  50. package/dist/wiki/pages.read.js +114 -0
  51. package/dist/wiki/pages.write.d.ts +109 -0
  52. package/dist/wiki/pages.write.js +201 -0
  53. package/package.json +36 -0
  54. package/skills/historian/SKILL.md +294 -0
  55. package/skills/historian/references/adapting-your-own-wiki.md +53 -0
  56. package/skills/historian/references/genres.md +160 -0
  57. package/skills/historian/references/rules.md +30 -0
  58. package/skills/historian/references/style.md +84 -0
  59. package/skills/historian/references/wikijs-guide.md +87 -0
@@ -0,0 +1,558 @@
1
+ /**
2
+ * Bilingual G1–G4 page skeletons (template data).
3
+ *
4
+ * Provenance: `.omo/research/cross-cultural-wiki-writing-digest.md` (Genre
5
+ * templates + SYN-1..20) and `.omo/research/wikijs-2x-capabilities-digest.md`
6
+ * (expression syntax), vendored at `docs/research/*`.
7
+ *
8
+ * Contract of every skeleton constant:
9
+ * - Rubric dimension C anatomy: H1 placeholder → status line
10
+ * `**状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD`
11
+ * → one-line scope (`This page answers:` / `本页回答:`) → tail
12
+ * `Related Pages`/`相关页面` section with a real-link hint (SYN-9 fixed tail).
13
+ * - wiki.js 2.x expression pieces only: blockquote admonitions
14
+ * (`> …` + `{.is-info}`), `{.dense}` tables, `[^1]` footnotes.
15
+ * - FORBIDDEN: `{{toc}}`, `:::` containers, YAML frontmatter (`---` at pos 0) —
16
+ * wiki.js does not support them (they render as body text or v-pre escapes).
17
+ * - Language-native: zh skeletons use 中文节标题 and zh author guidance,
18
+ * en skeletons English; the bilingual pairs correspond section-for-section.
19
+ * - Inline `<!-- … -->` comments carry author guidance per section (what to
20
+ * write, length caps); placeholders are marked 占位/placeholder and must be
21
+ * replaced by the author before publishing.
22
+ *
23
+ * // allow: SIZE_OK — pure template data, one constant per (genre, lang);
24
+ * split across files would buy nothing (each pair is a single narrative).
25
+ */
26
+ /** G1 — 事件/复盘页 (incident postmortem), zh. */
27
+ export const G1_ZH = `# 页面标题(占位:写完后替换为实际标题,须与页面 title 一致)
28
+
29
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
30
+
31
+ **本页回答:** 一句话范围句(占位:本页记录哪次故障/事件的起因、影响与处置)
32
+
33
+ > **提示**
34
+ > 导言按金字塔结构结论先行,3–5 句:发生了什么 → 影响多大 → 根因是什么 → 已采取什么处置 → 教训。导言不得包含正文没有的事实。
35
+ {.is-info}
36
+
37
+ ## 摘要
38
+
39
+ <!-- 3–5 句金字塔导言:事件、影响、根因、处置、教训各一句;导言中的每个要点在正文都有展开。 -->
40
+
41
+ ## 元数据表
42
+
43
+ | 元数据 | 值 |
44
+ | --- | --- |
45
+ | 影响范围 | <!-- 哪些服务/用户/区域受影响 --> |
46
+ | 持续时间 | <!-- 起止时间,如 2026-09-01 14:02–15:47 (UTC+8) --> |
47
+ | 严重度 | <!-- P0/P1/P2(或 S1–S4),并写明判定依据 --> |
48
+
49
+ ## 背景
50
+
51
+ <!-- 前置上下文 2–5 句:系统本应如何工作,为何这次故障成为可能。 -->
52
+
53
+ ## 时间线
54
+
55
+ <!-- 只记可查证事实:以日志/告警为准,不以口述为准;相邻事件 ≠ 因果关系。每行必须填来源列。 -->
56
+
57
+ | 时间 | 事件 | 来源 |
58
+ | --- | --- | --- |
59
+ | YYYY-MM-DD HH:MM | <!-- 发生了什么 --> | <!-- 告警/日志/commit 链接 --> |
60
+
61
+ ## 量化影响
62
+
63
+ <!-- 用可验证数字说话:影响时长、受影响请求数/用户数/成本、SLO/SLA 偏离;小数不超过两位。 -->
64
+
65
+ ## 根因分析
66
+
67
+ **直接原因**:<!-- 触发故障的具体动作或条件 -->
68
+
69
+ **根本原因**:<!-- 让直接原因能够发生的设计/流程/依赖缺陷 -->
70
+
71
+ <!-- 5 Whys:从直接原因逐层追问,每层回答"Why"后追问下一层,最后收敛到根本原因。 -->
72
+ 1. Why: <!-- 第 1 层:为什么直接原因会发生 -->
73
+ 2. Why: <!-- 第 2 层 -->
74
+ 3. Why: <!-- 第 3 层 -->
75
+ 4. Why: <!-- 第 4 层 -->
76
+ 5. Why: <!-- 第 5 层:收敛到根本原因 -->
77
+
78
+ ## 处置
79
+
80
+ | 类别 | 措施 | 完成时间 |
81
+ | --- | --- | --- |
82
+ | 止血 | <!-- 立即恢复服务的动作 --> | <!-- YYYY-MM-DD HH:MM --> |
83
+ | 根治 | <!-- 防止再次发生的结构性修复 --> | <!-- 完成或计划时间 --> |
84
+
85
+ ## 行动项
86
+
87
+ | 措施 | 类型 | 负责人 | 期限 | 验证 | 状态 |
88
+ | --- | --- | --- | --- | --- | --- |
89
+ | <!-- 做什么 --> | <!-- prevent/mitigate/process --> | <!-- 负责人 --> | YYYY-MM-DD | <!-- 如何证明已完成 --> | <!-- 待办/进行中/已完成 --> |
90
+
91
+ <!-- 每个根因主题至少一个 prevent 行动项;验证列必须可检查,否则行动项不算完成。 -->
92
+
93
+ ## 教训
94
+
95
+ ### 做得好
96
+
97
+ <!-- 诚实记录有效做法;出过事不等于一切都不对。 -->
98
+
99
+ ### 做错
100
+
101
+ <!-- 写成可复用的反模式,禁止人身归因(无指责复盘)。 -->
102
+
103
+ ### 侥幸
104
+
105
+ <!-- 哪些环节差点更糟;哪些伏笔这次没爆、下次可能爆。 -->
106
+
107
+ ## 附录
108
+
109
+ <!-- 原始证据:告警截图、日志片段、commit/PR 链接。脚注示例: -->
110
+ 见脚注[^1]。
111
+
112
+ [^1]: 来源链接(替换为真实出处)
113
+
114
+ ## 相关页面
115
+
116
+ <!-- 列出与本页互链的真实页面路径,例如:[服务架构](./architecture)。 -->`;
117
+ /** G1 — incident postmortem, en (section-for-section twin of G1_ZH). */
118
+ export const G1_EN = `# Page Title (placeholder: replace with the real title, must match the page title)
119
+
120
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
121
+
122
+ **This page answers:** one-line scope sentence (placeholder: which incident this page records, its impact and handling)
123
+
124
+ > **Tip**
125
+ > Lead follows an inverted pyramid, 3–5 sentences: what happened → how big the impact → root cause → remediation → lesson. No fact in the lead that is not in the body.
126
+ {.is-info}
127
+
128
+ ## Summary
129
+
130
+ <!-- 3–5 sentence pyramid lead: one sentence each for event, impact, root cause, remediation, lesson. -->
131
+
132
+ ## Metadata
133
+
134
+ | Field | Value |
135
+ | --- | --- |
136
+ | Blast radius | <!-- services/users/regions affected --> |
137
+ | Duration | <!-- start–end, e.g. 2026-09-01 14:02–15:47 (UTC+8) --> |
138
+ | Severity | <!-- P0/P1/P2 (or S1–S4) with the basis for the rating --> |
139
+
140
+ ## Background
141
+
142
+ <!-- 2–5 sentences of context: how the system was supposed to work, and what made the incident possible. -->
143
+
144
+ ## Timeline
145
+
146
+ <!-- Verifiable facts only: log/alert-based, not memory-based; adjacent events ≠ causation. Every row needs its source column filled. -->
147
+
148
+ | Time | Event | Source |
149
+ | --- | --- | --- |
150
+ | YYYY-MM-DD HH:MM | <!-- what happened --> | <!-- alert/log/commit link --> |
151
+
152
+ ## Quantified Impact
153
+
154
+ <!-- Numbers: duration, affected requests/users, cost, SLO/SLA deviation; no float beyond two decimal places. -->
155
+
156
+ ## Root Cause
157
+
158
+ **Direct cause**: <!-- the concrete trigger -->
159
+
160
+ **Root cause**: <!-- the design/process/dependency flaw that let the trigger happen -->
161
+
162
+ <!-- 5 Whys: five consecutive why-layers from the trigger to the root, each layer answered before the next question is asked. -->
163
+ 1. Why: <!-- layer 1: why did the direct cause happen -->
164
+ 2. Why: <!-- layer 2 -->
165
+ 3. Why: <!-- layer 3 -->
166
+ 4. Why: <!-- layer 4 -->
167
+ 5. Why: <!-- layer 5: converges on the root cause -->
168
+
169
+ ## Remediation
170
+
171
+ | Kind | Action | Done |
172
+ | --- | --- | --- |
173
+ | Stop-the-bleed | <!-- immediate restore action --> | <!-- YYYY-MM-DD HH:MM --> |
174
+ | Fix-the-root | <!-- structural fix preventing recurrence --> | <!-- completed or planned date --> |
175
+
176
+ ## Action Items
177
+
178
+ | Action | Type | Owner | Due | Verification | Status |
179
+ | --- | --- | --- | --- | --- | --- |
180
+ | <!-- what to do --> | <!-- prevent/mitigate/process --> | <!-- owner --> | YYYY-MM-DD | <!-- how to prove it is done --> | <!-- todo/in progress/done --> |
181
+
182
+ <!-- At least one prevent item per root-cause theme; an action item without a checkable verification is not done. -->
183
+
184
+ ## Lessons
185
+
186
+ ### What Went Well
187
+
188
+ <!-- Honest: an incident does not invalidate everything that worked. -->
189
+
190
+ ### What Went Wrong
191
+
192
+ <!-- Reusable anti-patterns; never blame people (blameless postmortem). -->
193
+
194
+ ### Lucky Breaks
195
+
196
+ <!-- What almost made it worse? Which lurking risk will bite next time? -->
197
+
198
+ ## Appendix
199
+
200
+ <!-- Raw evidence: alert screenshots, log excerpts, commit/PR links. Footnote example: -->
201
+ See footnote[^1].
202
+
203
+ [^1]: Source link (replace with the real source)
204
+
205
+ ## Related Pages
206
+
207
+ <!-- List real page paths that link here and back, e.g.: [Service architecture](./architecture). -->`;
208
+ /** G2 — 对比/选型页 (comparison / selection), zh. */
209
+ export const G2_ZH = `# 页面标题(占位:写完后替换为实际标题,须与页面 title 一致)
210
+
211
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
212
+
213
+ **本页回答:** 一句话范围句(占位:本页在哪些对象之间、按什么维度对比,结论是什么)
214
+
215
+ ## 结论先行
216
+
217
+ <!-- 第一段直接给答案:选哪个对象、为什么;导言不得包含正文没有的事实。 -->
218
+
219
+ > **选型建议**
220
+ > 选择 对象 A:一句话理由。若 前提 X 不成立,见「选型建议」小节的条件式清单。
221
+ {.is-info}
222
+
223
+ ## 维度定义
224
+
225
+ | 维度 | 为什么重要 | 数据来源 |
226
+ | --- | --- | --- |
227
+ | <!-- 如:p99 延迟 --> | <!-- 该维度如何影响决策 --> | <!-- 官方文档/基准/实测 --> |
228
+
229
+ <!-- 每个维度一句"为什么重要",读者才能判断该维度是否适用于自己的场景。 -->
230
+
231
+ ## 对象概览
232
+
233
+ <!-- 每个对象一个小节或描述列表:一句话定位 + 关键特性;被推荐对象放在最前。 -->
234
+
235
+ ## 对比
236
+
237
+ <!-- 行 = 维度,列 = 对象与来源列;行序固定;禁止合并单元格。 -->
238
+
239
+ | 维度 | 对象 A | 对象 B | 对象 C | 来源 |
240
+ | --- | --- | --- | --- | --- |
241
+ | <!-- 维度 --> | <!-- 值 --> | <!-- 值 --> | <!-- 值 --> | <!-- 出处链接 --> |
242
+ {.dense}
243
+
244
+ ## 基准与方法
245
+
246
+ <!-- 测试环境、版本号、负载、采样时长——方法透明,别人才能复现或质疑。 -->
247
+
248
+ ## 选型建议
249
+
250
+ <!-- 条件式建议:不同前提 → 不同选择,每行一条。 -->
251
+ - 如果 前提(如团队规模/流量/预算),选择 对象 A,因为 一句话理由
252
+ - 如果 前提,选择 对象 B,因为 一句话理由
253
+ - 如果 前提,选择 对象 C,因为 一句话理由
254
+
255
+ ## 相关页面
256
+
257
+ <!-- 列出与本页互链的真实页面路径。 -->`;
258
+ /** G2 — comparison / selection, en (section-for-section twin of G2_ZH). */
259
+ export const G2_EN = `# Page Title (placeholder: replace with the real title, must match the page title)
260
+
261
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
262
+
263
+ **This page answers:** one-line scope sentence (placeholder: what is compared, on which dimensions, and the pick)
264
+
265
+ ## Bottom Line
266
+
267
+ <!-- The first paragraph IS the answer: which option and why; no fact in the lead that is not in the body. -->
268
+
269
+ > **Recommendation**
270
+ > Choose Option A: one-line reason. If premise X does not hold, see the conditional list in "Recommendation".
271
+ {.is-info}
272
+
273
+ ## Dimension Definitions
274
+
275
+ | Dimension | Why it matters | Data source |
276
+ | --- | --- | --- |
277
+ | <!-- e.g. p99 latency --> | <!-- how it affects the decision --> | <!-- docs/benchmark/measurement --> |
278
+
279
+ <!-- One "why it matters" sentence per dimension so readers can judge fit for their own case. -->
280
+
281
+ ## Object Overview
282
+
283
+ <!-- One short subsection or description list per object: one-line positioning + key traits; recommended object first. -->
284
+
285
+ ## Comparison
286
+
287
+ <!-- Rows = dimensions; columns = options plus a source column; fixed row order; no merged cells. -->
288
+
289
+ | Dimension | Option A | Option B | Option C | Source |
290
+ | --- | --- | --- | --- | --- |
291
+ | <!-- dimension --> | <!-- value --> | <!-- value --> | <!-- value --> | <!-- citation link --> |
292
+ {.dense}
293
+
294
+ ## Methodology
295
+
296
+ <!-- Environment, versions, load, sample window — a transparent method that others can reproduce or contest. -->
297
+
298
+ ## Recommendation
299
+
300
+ <!-- Conditional advice: different premises → different picks, one line each. -->
301
+ - If premise (team size / traffic / budget), choose Option A, because one-line reason
302
+ - If premise, choose Option B, because one-line reason
303
+ - If premise, choose Option C, because one-line reason
304
+
305
+ ## Related Pages
306
+
307
+ <!-- List real page paths that link here and back. -->`;
308
+ /** G3 — 清单/参考页 (inventory / reference), zh. */
309
+ export const G3_ZH = `# 页面标题(占位:写完后替换为实际标题,须与页面 title 一致)
310
+
311
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
312
+
313
+ **本页回答:** 一句话范围句(占位:本页收录哪类条目、覆盖到哪里、不覆盖什么)
314
+
315
+ ## 范围声明
316
+
317
+ <!-- 明确收录/不收录边界:覆盖 X、不覆盖 Y,入选标准一句话;没有范围声明的清单,读者无法判断"没出现 = 不存在"还是"没收录"。 -->
318
+
319
+ > **提示**
320
+ > 清单页导言必须先声明范围,再给条目。
321
+ {.is-info}
322
+
323
+ ## 目录(结构镜像)
324
+
325
+ <!-- 小节顺序镜像被测系统/命令树的真实结构(map principle):读者按目录即可找到条目。 -->
326
+
327
+ ## 条目表
328
+
329
+ | 条目 | 说明 | 用法/命令 | 相关链接 |
330
+ | --- | --- | --- | --- |
331
+ | <!-- 名称 --> | <!-- 一句话说明 --> | <!-- 平行句式的用法 --> | <!-- 已存在的页面 --> |
332
+ {.dense}
333
+
334
+ <!-- 平行句式:每个单元格用同一语法结构;日期一律写绝对日期(YYYY-MM-DD),不写"最近";只链接已存在页面。 -->
335
+
336
+ ## 维护说明
337
+
338
+ <!-- 更新频率、谁维护、新增条目的检查项(与同类条目同构、有来源、链接存在)。 -->
339
+
340
+ ## 相关页面
341
+
342
+ <!-- 列出与本页互链的真实页面路径。 -->`;
343
+ /** G3 — inventory / reference, en (section-for-section twin of G3_ZH). */
344
+ export const G3_EN = `# Page Title (placeholder: replace with the real title, must match the page title)
345
+
346
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
347
+
348
+ **This page answers:** one-line scope sentence (placeholder: which entries are covered, up to what boundary)
349
+
350
+ ## Scope Statement
351
+
352
+ <!-- State the inclusion/exclusion boundary explicitly: covers X, not Y, and the one-line admission bar; without it readers cannot tell "absent" from "not collected". -->
353
+
354
+ > **Tip**
355
+ > A reference page must state its scope before listing entries.
356
+ {.is-info}
357
+
358
+ ## Contents (Structure Mirror)
359
+
360
+ <!-- Order the sections to mirror the real structure of the system/command tree (map principle): readers find entries by following the table of contents. -->
361
+
362
+ ## Entry Table
363
+
364
+ | Entry | Description | Usage / Command | Related link |
365
+ | --- | --- | --- | --- |
366
+ | <!-- name --> | <!-- one-line description --> | <!-- parallel-syntax usage --> | <!-- existing page --> |
367
+ {.dense}
368
+
369
+ <!-- Parallel syntax: every cell uses the same grammatical shape; dates are always absolute (YYYY-MM-DD), never "recently"; link only pages that already exist. -->
370
+
371
+ ## Maintenance Note
372
+
373
+ <!-- Update cadence, who maintains it, the checklist for new entries (same shape as siblings, sourced, links resolve). -->
374
+
375
+ ## Related Pages
376
+
377
+ <!-- List real page paths that link here and back. -->`;
378
+ /** G4 — 概念/原理解析页 (concept / explanation), zh. */
379
+ export const G4_ZH = `# 页面标题(占位:写完后替换为实际标题,须与页面 title 一致)
380
+
381
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
382
+
383
+ **本页回答:** 一句话范围句(占位:本页解释哪个概念,读者看完能理解什么)
384
+
385
+ ## 定义与收录理由
386
+
387
+ <!-- 定义先行且门外汉可懂,不依赖行话;收录理由 = 这个概念为何值得单独成页。 -->
388
+
389
+ > **提示**
390
+ > 定义必须让没有背景的读者也能读懂;正文中第一个出现的不常见术语当场解释。
391
+ {.is-info}
392
+
393
+ ## 方面一(占位:最重要的方面,改成描述性标题)
394
+
395
+ <!-- H2 小节按重要性降序排列;每个小节先总结后展开;每层小节总结下一层内容。 -->
396
+
397
+ ## 方面二(占位:次重要的方面)
398
+
399
+ <!-- 若只有一个方面,删掉多余小节;禁止"其他/杂项"类 catch-all 小节。 -->
400
+
401
+ ## 机制说明
402
+
403
+ <!-- 概念如何运作:输入 → 过程 → 输出,配必要示例;≥3 字段的结构化数据入表。 -->
404
+
405
+ ## 归因与观点
406
+
407
+ <!-- 明确标注:哪些是社区共识(附来源),哪些是作者观点(写明"本文作者认为…");评价性表述必须归属,不得代 wiki 自行评断。 -->
408
+
409
+ ## 参见
410
+
411
+ <!-- 可选:与此概念最直接相关的页面;无直接相关页面时可并入「相关页面」。 -->
412
+
413
+ ## 相关页面
414
+
415
+ <!-- 列出与本页互链的真实页面路径。 -->`;
416
+ /** G4 — concept / explanation, en (section-for-section twin of G4_ZH). */
417
+ export const G4_EN = `# Page Title (placeholder: replace with the real title, must match the page title)
418
+
419
+ **状态/Status**: Active <!-- or Historical/Superseded --> · **日期/Date**: YYYY-MM-DD
420
+
421
+ **This page answers:** one-line scope sentence (placeholder: which concept is explained and what the reader will understand)
422
+
423
+ ## Definition and Rationale
424
+
425
+ <!-- Define first, readable without background, no jargon assumptions; the rationale = why this concept deserves its own page. -->
426
+
427
+ > **Tip**
428
+ > The definition must be understandable without background; explain the first uncommon term it uses right there.
429
+ {.is-info}
430
+
431
+ ## Aspect 1 (placeholder: most important aspect; rename to a descriptive heading)
432
+
433
+ <!-- H2 sections sorted by importance, most important first; each section summarizes before expanding; each layer summarizes the layer below it. -->
434
+
435
+ ## Aspect 2 (placeholder: the second-most important aspect)
436
+
437
+ <!-- Delete surplus sections when there is only one aspect; no "other/miscellaneous" catch-all sections. -->
438
+
439
+ ## How It Works
440
+
441
+ <!-- How the concept operates: input → process → output, with a working example; structured data with ≥3 fields goes into a table. -->
442
+
443
+ ## Attribution and Opinion
444
+
445
+ <!-- Mark explicitly what is community consensus (with sources) and what is the author's view (state "the author believes…"); evaluative language must be attributed, never the wiki's own judgment. -->
446
+
447
+ ## See Also
448
+
449
+ <!-- Optional: the pages most directly related to this concept; fold into "Related Pages" when there are none. -->
450
+
451
+ ## Related Pages
452
+
453
+ <!-- List real page paths that link here and back. -->`;
454
+ /** G5 — 现状卡/部署现状账本页 (current-state ledger), zh. Status + tables only:
455
+ * one authoritative snapshot of what is deployed/running NOW, per-row
456
+ * last-verified dates, agent-executable re-check commands. Narrative history
457
+ * belongs to G1 event pages, linked from 变更记录. */
458
+ export const G5_ZH = `# 页面标题(占位:写完后替换为实际标题,须与页面 title 一致)
459
+
460
+ **状态/Status**: Active <!-- or Superseded-by: <path> / Deprecated --> · **日期/Date**: YYYY-MM-DD
461
+
462
+ **本页回答:** 当前部署状态(占位:写明范围)
463
+
464
+ > **提示**
465
+ > 现状卡只存事实快照:一行一个部署物。
466
+ > 叙述性历史写进 G1 事件页,从变更记录链过去。
467
+ {.is-info}
468
+
469
+ ## 部署物清单
470
+
471
+ | 组件 | 版本 | 端口/路径 | 端点 | 依赖 | 上次核实于 |
472
+ | --- | --- | --- | --- | --- | --- |
473
+ | example-api | 1.2.3 | 8000 | http://example.com:8000/health | postgres | YYYY-MM-DD |
474
+
475
+ <!-- 每行须能被验证方法当场复核。核实日期不得留空。 -->
476
+
477
+ ## 依赖与集成
478
+
479
+ | 集成对象 | 方向 | 用途 | 失效影响 |
480
+ | --- | --- | --- | --- |
481
+
482
+ <!-- 只列正在生效的集成。已解除的记入变更记录。 -->
483
+
484
+ ## 失效策略
485
+
486
+ <!-- 写明使本卡过期的事件。例:版本变更、端口调整、依赖下线。 -->
487
+ <!-- 复查节奏:默认每 30 天逐行重跑验证命令。 -->
488
+
489
+ ## 验证方法
490
+
491
+ | 组件 | 复核命令 | 预期结果 |
492
+ | --- | --- | --- |
493
+ | example-api | \`curl -s http://example.com:8000/health\` | HTTP 200 |
494
+
495
+ <!-- 命令须 agent 可直接执行。禁止登录机器看看式模糊描述。 -->
496
+
497
+ ## 变更记录
498
+
499
+ | 日期 | 变更 | 依据 |
500
+ | --- | --- | --- |
501
+ | YYYY-MM-DD | 初版快照 | — |
502
+
503
+ <!-- 追加式小表:只记影响清单行的变更。完整历史写 G1 事件页并互链。 -->
504
+
505
+ ## 相关页面
506
+
507
+ <!-- 列出互链的真实页面路径。事故史放 G1 页并在依据列引用。 -->`;
508
+ /** G5 — current-state ledger, en (section-for-section twin of G5_ZH). */
509
+ export const G5_EN = `# Page Title (placeholder: replace with the real title, must match the page title)
510
+
511
+ **状态/Status**: Active <!-- or Superseded-by: <path> / Deprecated --> · **日期/Date**: YYYY-MM-DD
512
+
513
+ **This page answers:** what is deployed and running right now (placeholder: name the system and scope)
514
+
515
+ > **Tip**
516
+ > A ledger stores fact snapshots, not prose: one deployed component per row.
517
+ > Narrative history belongs in G1 event pages, linked from the change log.
518
+ {.is-info}
519
+
520
+ ## Deployed Components
521
+
522
+ | Component | Version | Port/Path | Endpoint | Depends on | Last verified |
523
+ | --- | --- | --- | --- | --- | --- |
524
+ | example-api | 1.2.3 | 8000 | http://example.com:8000/health | postgres | YYYY-MM-DD |
525
+
526
+ <!-- Every row must be re-checkable by a command in Verification. Never leave the date blank. -->
527
+
528
+ ## Dependencies and Integration
529
+
530
+ | Counterpart | Direction | Purpose | Impact if gone |
531
+ | --- | --- | --- | --- |
532
+
533
+ <!-- List only integrations in force. Record removed ones in the change log. -->
534
+
535
+ ## Invalidation Policy
536
+
537
+ <!-- Name the events that stale this card: version bumps, port moves, dependency retirements. -->
538
+ <!-- Review cadence: re-run every verification command every 30 days by default. -->
539
+
540
+ ## Verification
541
+
542
+ | Component | Re-check command | Expected result |
543
+ | --- | --- | --- |
544
+ | example-api | \`curl -s http://example.com:8000/health\` | HTTP 200 |
545
+
546
+ <!-- Commands must be agent-executable as written. Vague steps like log in and look are forbidden. -->
547
+
548
+ ## Change Log
549
+
550
+ | Date | Change | Evidence |
551
+ | --- | --- | --- |
552
+ | YYYY-MM-DD | initial snapshot | — |
553
+
554
+ <!-- Append-only mini table for list-affecting changes. Full history lives in G1 event pages. -->
555
+
556
+ ## Related Pages
557
+
558
+ <!-- List the real page paths that link here and back. Event histories go in G1 pages, cited in Evidence. -->`;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * historian_page_create: content-present → engine createPage (twin semantics
3
+ * per the engine contract); content ABSENT → pure-local genre template mode
4
+ * (classify + skeleton, ZERO GraphQL writes — pitfall #4 avoidance: the wiki
5
+ * rejects empty content, so an empty create must never reach the network).
6
+ */
7
+ import { type ToolDefinition } from '@opencode-ai/plugin';
8
+ import { type ToolDeps } from './shared.js';
9
+ export declare function makeCreateTool(deps: ToolDeps): ToolDefinition;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * historian_page_create: content-present → engine createPage (twin semantics
3
+ * per the engine contract); content ABSENT → pure-local genre template mode
4
+ * (classify + skeleton, ZERO GraphQL writes — pitfall #4 avoidance: the wiki
5
+ * rejects empty content, so an empty create must never reach the network).
6
+ */
7
+ import { tool } from '@opencode-ai/plugin';
8
+ import { validatePath } from '../wiki/locale.js';
9
+ import { createPage } from '../wiki/pages.js';
10
+ import { classifyGenre, genreSkeleton } from '../templates/genres.js';
11
+ import { errEnvelope, okJson, urlPair, URL_MANDATE, pageDeps } from './shared.js';
12
+ const s = tool.schema;
13
+ const GENRES = ['G1', 'G2', 'G3', 'G4', 'G5'];
14
+ const ARGS_SHAPE = {
15
+ path: s.string().describe('Wiki path, e.g. docs/guides/foo (first segment must NOT look like a locale code)'),
16
+ title: s.string().describe('Page title'),
17
+ content: s.string().optional().describe('Page body (markdown). ABSENT → local template mode, nothing written'),
18
+ genre: s.enum(GENRES).optional().describe('Genre hint: G1..G5 (template mode / classification)'),
19
+ locale: s.enum(['en', 'zh']).default('en'),
20
+ isPublished: s.boolean().default(true),
21
+ tags: s.array(s.string()).default([]),
22
+ twin: s.boolean().default(true).describe('Auto-create the opposite-locale twin via translation'),
23
+ description: s.string().optional(),
24
+ };
25
+ const ArgsSchema = s.object(ARGS_SHAPE);
26
+ export function makeCreateTool(deps) {
27
+ return tool({
28
+ description: `Create a wiki page: primary locale content plus an optional auto-translated twin. ` +
29
+ `Pass NO content to get a pure-local genre template (classification + skeleton, nothing is written to the wiki). ` +
30
+ `${URL_MANDATE}.`,
31
+ args: ARGS_SHAPE,
32
+ execute: async (raw) => {
33
+ const args = ArgsSchema.parse(raw);
34
+ try {
35
+ validatePath(args.path);
36
+ }
37
+ catch (err) {
38
+ return errEnvelope(err);
39
+ }
40
+ if (args.content === undefined || args.content.trim() === '') {
41
+ const genre = args.genre ?? classifyGenre({ title: args.title, body: args.description ?? '' }).genre;
42
+ return okJson({
43
+ mode: 'template',
44
+ genre,
45
+ locale: args.locale,
46
+ skeleton: genreSkeleton(genre, args.locale),
47
+ note: 'Nothing was written to the wiki (template mode, no content). Fill the skeleton and call historian_page_create again with content.',
48
+ });
49
+ }
50
+ try {
51
+ const result = await createPage(pageDeps(deps), {
52
+ path: args.path,
53
+ locale: args.locale,
54
+ title: args.title,
55
+ content: args.content,
56
+ tags: args.tags,
57
+ isPublished: args.isPublished,
58
+ twin: args.twin,
59
+ description: args.description,
60
+ });
61
+ return okJson({
62
+ mode: 'create',
63
+ path: args.path,
64
+ locale: args.locale,
65
+ pageId: result.pageId,
66
+ twinStatus: result.twinStatus,
67
+ twinReason: result.twinReason,
68
+ twinId: result.twinId,
69
+ urls: urlPair(result),
70
+ });
71
+ }
72
+ catch (err) {
73
+ return errEnvelope(err);
74
+ }
75
+ },
76
+ });
77
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * historian_translate_snippet + historian_map: tools that never write to the
3
+ * wiki engine (map refresh writes its cache page + mirror via the engine, but
4
+ * only on the explicit refresh action). translate_snippet surfaces engine
5
+ * TranslateError causes as structured output — never a throw.
6
+ */
7
+ import { type ToolDefinition } from '@opencode-ai/plugin';
8
+ import { type ToolDeps } from './shared.js';
9
+ export declare function makeTranslateSnippetTool(deps: ToolDeps): ToolDefinition;
10
+ export declare function makeMapTool(deps: ToolDeps): ToolDefinition;