@namewta/speculo 0.8.2 → 0.8.4

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 (34) hide show
  1. package/README.md +2 -1
  2. package/package.json +1 -1
  3. package/template/.speculo/README.md +8 -6
  4. package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +1 -1
  5. package/template/canonical/canonical-specdev-goal-plan.md +1 -1
  6. package/template/canonical/canonical-specdev-grill-with-docs.md +1 -1
  7. package/template/canonical/canonical-specdev-spec.md +1 -1
  8. package/template/canonical/canonical-specdev-tickets.md +1 -1
  9. package/template/commands/archive-and-consolidate.md +4 -4
  10. package/template/commands/docs-sync.md +4 -4
  11. package/template/commands/git-repository-audit.md +7 -7
  12. package/template/commands/handoff.md +2 -2
  13. package/template/commands/retro.md +6 -6
  14. package/template/commands/status.md +4 -4
  15. package/template/skills/archive-and-consolidate/SKILL.md +3 -3
  16. package/template/skills/docs-sync/assets/state-template.json +1 -1
  17. package/template/skills/docs-sync/assets/workflow-scope-template.json +1 -1
  18. package/template/skills/docs-sync/references/git-state-contract.md +2 -2
  19. package/template/skills/docs-sync/references/workflow-scope-contract.md +3 -3
  20. package/template/skills/github-npm-ops/references/preflight-checklist.md +1 -1
  21. package/template/skills/github-npm-ops/references/release-notes-injection.md +1 -1
  22. package/template/skills/github-npm-ops/references/release-pipeline.md +4 -4
  23. package/template/skills/github-npm-ops/references/version-bump-flow.md +2 -2
  24. package/template/skills/speculo-retro/references/friction-taxonomy.md +2 -2
  25. package/template/skills/speculo-retro/references/issue-drafting-sop.md +5 -5
  26. package/template/skills/upstream-fork-sync/SKILL.md +83 -0
  27. package/template/skills/upstream-fork-sync/references/report-contract.md +40 -0
  28. package/template/skills/upstream-fork-sync/references/repository-contract.md +54 -0
  29. package/template/skills/upstream-fork-sync/references/state-schema.md +55 -0
  30. package/template/skills/upstream-fork-sync/scripts/upstream-sync.mjs +740 -0
  31. package/template/workflows/specdev/E-eli5/E-eli5.md +75 -15
  32. package/template/workflows/specdev/INDEX.md +5 -5
  33. package/template/workflows/specdev/common/rules/artifact-contract.md +1 -1
  34. package/template/workflows/specdev/common/tools/validate-specdev.mjs +50 -11
@@ -2,34 +2,94 @@
2
2
  id: specdev/eli5
3
3
  type: workflow-entry
4
4
  workflow: specdev
5
- name: 五岁解释
6
- description: 像对五岁的我一样解释一个主题。当用户要求用极其简单的图片解释某件事如何运作时,生成大图、少字的持久化 HTML 图解。
5
+ name: 零基础新生解释
6
+ description: 面向刚上大一、没有专业背景的读者解释一个主题;用 Markdown 和 ASCII 图解说明概念、数据与调用如何流动。
7
+ keywords: [eli5, 零基础, 大一新生, Markdown, ASCII]
7
8
  ---
9
+ # ELI5:给零基础新生的图解
8
10
 
9
- # eli5:像对五岁的我一样解释
11
+ ## 读者与职责
10
12
 
11
- ## 原作者核心(完整中文转写)
13
+ 读者是刚入大学、没有专业背景(零专业背景)的新生。读者能理解日常因果和简单流程,但不应被假定知道代码、网络、数学或行业背景。
12
14
 
13
- 像对五岁的我一样解释一个主题。要求用极其简单的图片解释某件事如何运作时,使用此 Work
15
+ Work 只解释,不作产品决定、架构决定或实现授权。它把已验证的事实写成一个可恢复的 Markdown 图解;图比段落更先出现,文字只负责读懂图。
14
16
 
15
- 像对一个完全不了解这个主题的五岁孩子一样解释,使用一个大图、少字的 HTML 工件。
17
+ ```text
18
+ 已验证的事实
19
+ |
20
+ v
21
+ 拆成小问题和小部件
22
+ |
23
+ v
24
+ ASCII 全图 + 分步图 + 简短说明
25
+ |
26
+ v
27
+ 01_<topic>.md、02_<topic>.md、...(给零基础新生的解释)
28
+ |
29
+ v
30
+ 图解索引(所有图解的目录)
31
+ ```
16
32
 
17
33
  主题:`$ARGUMENTS`
18
34
 
19
- 这里的“五岁”是字面标准,不只是“初学者”的别称:假定读者真的只有五岁,没有专业词汇、背景知识或抽象模型。保留事实准确性,但用熟悉的物体、动作、因果和类比来解释。
35
+ ## 输出格式
36
+
37
+ 在 `<Path>{roots.state}/specdev/changes/{change}/</Path>` 内原子写入一份新的 `<Path>{roots.state}/specdev/changes/{change}/{number}_{topic}.md</Path>`,以及索引 `<Path>{roots.state}/specdev/changes/{change}/eli_index.md</Path>`。文档必须是纯 Markdown,不生成 HTML、CSS、SVG、图片链接或浏览器专属交互。
38
+
39
+ `<number>` 是两位起始、持续递增的序号:先读取索引和同目录已有的图解文件,取最大序号加一,因此第一次为 `01`,下一次为 `02`;不为旧文件重编号。`<topic>` 是主题的简短、可作文件名的标签,可使用中文、字母、数字、`-` 或 `_`,但不能含空格、`/`、`\\` 或 `..`。同主题再次解释也创建新编号文件。
40
+
41
+ 索引是唯一目录,使用下列 Markdown 表格;每新增一份图解就在表末追加一行,并保留既有行。文件列只写同目录的文件名:
42
+
43
+ ```markdown
44
+ # ELI5 图解索引
45
+
46
+ | 编号 | 文件 | 主题 | 简介 |
47
+ | --- | --- | --- | --- |
48
+ | 01 | 01_<topic>.md | <主题> | <一句话说明它解释什么> |
49
+ ```
50
+
51
+ 按主题选择最贴切的图,但优先用多个短小 ASCII 图代替长文字:
52
+
53
+ ```text
54
+ 结构图:
55
+ [系统]
56
+ |
57
+ +-- [部件 A]
58
+ +-- [部件 B]
59
+
60
+ 数据流图:
61
+ [输入] -> [处理] -> [结果]
62
+
63
+ 调用流图:
64
+ [用户动作] -> [入口] -> [服务] -> [回应]
65
+
66
+ 状态变化图:
67
+ [等待] -> [进行中] -> [完成]
68
+ ```
69
+
70
+ 每份图解至少包含以下四节:
71
+
72
+ 1. `## 先看全图`:一个能说清“谁和谁有关”的 ASCII 图。
73
+ 2. `## 一步一步看`:按箭头顺序解释。流程、数据或调用会移动时,再给对应的 ASCII 图。
74
+ 3. `## 术语小词典`:只保留读图必需的词。每个词先用日常语言解释,再给它的专业名字。例如:`临时便签(缓存)`,意思是“把常用结果先放在手边,下一次不用重新找”。
75
+
76
+ 图中的方框名称使用普通名词和动词,不用缩写;箭头必须有方向。一个图只讲一个问题。确有边界、失败或例外时,单独画一张小图说明,不把它塞进主图。
20
77
 
21
78
  ## 执行
22
79
 
23
80
  1. 读取 `<Path>{roots.workflows}/specdev/INDEX.md</Path>`、全局状态和当前 change 状态。选择用户指定或唯一活跃的 change;没有时按 SpecDev 启动协议创建。`current_work` 为空时设为 `specdev/eli5`;若指向其他 Work,先完成显式交接。
24
- 2. 将调用中的 `$ARGUMENTS` 解析为主题;直接提出的图解请求以用户最新消息为主题。主题缺失时只询问主题,不猜测。
25
- 3. 按需读取当前 change 工件、项目事实和可靠来源。先找出一个孩子必须理解的核心因果,再选择一个熟悉、不会歪曲事实的视觉类比。
26
- 4. 原子写入 `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>`。页面必须是可直接打开的完整 HTML,以大图为主、文字为辅;避免术语、长段落和先备知识。需要术语时,先用孩子能懂的话解释。
27
- 5. 检查 HTML 可打开、主题明确、主要解释由图片承担、文字足够少,而且一个真正的五岁孩子仅看页面就能说出“它是什么”和“它怎么运作”。可用浏览器时实际打开检查;不可用时做静态检查并说明限制。
28
- 6. 运行 `<Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path>` `--stage eli5`。成功后把 `specdev/eli5` 去重加入 `works_run`,清空 `current_work`,并返回 HTML 完整路径;失败时保留 `current_work` 和阻塞原因,便于恢复。
81
+ 2. 将调用中的 `$ARGUMENTS` 解析为主题;直接提出的图解请求以用户最新消息为主题。主题缺失时只询问主题,不猜测。先写下读者要带走的三个答案:它是什么、为什么需要它、它怎样流动或被调用。
82
+ 3. 按需读取当前 change 工件、项目事实和可靠来源。区分已验证事实、便于理解的类比和未知处;类比只能帮助理解,不能替代事实或掩盖边界。
83
+ 4. 先画 `先看全图`,再按实际关系补充结构图、数据流图、调用流图或状态变化图。每张图旁只用短句解释箭头;避免长段落、术语堆叠、缩写和先备知识。
84
+ 5. 首次使用术语时,先写日常解释,再在括号中给专业名字。读完后从读者角度检查:没有背景知识的人能否仅靠图和短句复述三个答案;若不能,拆图或替换术语,不增加大段说明。
85
+ 6. 读取 `<Path>{roots.state}/specdev/changes/{change}/eli_index.md</Path>` 和已有图解文件。从最大序号计算下一个编号,创建新的图解文件,再原子更新索引;不覆盖、重命名或重排已有图解。重读确认新文件是 Markdown,包含四个必需章节、至少一个 ASCII 图和没有 HTML 标记或图片依赖,且索引的文件名、主题和简介都与新文件对应。
86
+ 7. 运行 `<Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path>` 的 `--stage eli5`。成功后把 `specdev/eli5` 去重加入 `works_run`,清空 `current_work`,并返回 Markdown 完整路径;失败时保留 `current_work` 和阻塞原因,便于恢复。
29
87
 
30
88
  ## 完成标准
31
89
 
32
- - `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>` 存在且是完整 HTML。
33
- - 页面确实面向五岁、零背景读者,并以大图、少字解释主题,而不是把普通长文换成更大的字号。
34
- - 解释简单但不虚假;类比的边界不会让读者形成相反理解。
90
+ - `<Path>{roots.state}/specdev/changes/{change}/eli_index.md</Path>` 存在,按序列出每份图解的编号、文件、主题和简介;每个文件名都对应同目录真实文件。
91
+ - 新的 `<Path>{roots.state}/specdev/changes/{change}/{number}_{topic}.md</Path>` 存在,是纯 Markdown,并含有全部四个必需章节和至少一个 ASCII 图;编号比既有最大编号大一,旧文件未被重排或覆盖。
92
+ - 文档面向刚上大一、没有专业背景的读者;用图和短句解释主题,而不是把专业长文换成更简单的字。
93
+ - 图解覆盖主题需要的结构、数据流、调用流或状态变化;能画图的地方优先画图,且每张图的箭头方向与事实一致。
94
+ - 术语首次出现前有日常解释;类比不把读者带向相反结论。
35
95
  - 状态已原子更新;除当前 change 工件外,没有修改项目代码、永久知识或远程系统。
@@ -3,7 +3,7 @@ id: specdev
3
3
  type: workflow
4
4
  workflow: specdev
5
5
  name: SpecDev Workflow
6
- description: 以本地工件为唯一开发权威,从来源冻结、诊断、设计、五岁图解、原型、规格、Ticket、编排和审查推进到证据驱动实现、远程 reconcile 与知识归档。
6
+ description: 以本地工件为唯一开发权威,从来源冻结、诊断、设计、零基础新生图解、原型、规格、Ticket、编排和审查推进到证据驱动实现、远程 reconcile 与知识归档。
7
7
  keywords: [specdev, local-first, 规格驱动开发, decision-complete, eli5, prototype, code-review, TDD, 证据]
8
8
  ---
9
9
 
@@ -59,7 +59,7 @@ Archive 归档历史并将经验证知识提升为当前长期知识
59
59
  - `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`
60
60
  - `<Path>{roots.state}/specdev/changes/{change}/prototypes/</Path>`
61
61
  - `<Path>{roots.state}/specdev/changes/{change}/questionnaires/</Path>`
62
- - `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>`
62
+ - `<Path>{roots.state}/specdev/changes/{change}/eli_index.md</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/<number>_<topic>.md</Path>`
63
63
 
64
64
  工件职责和冲突裁决位于 `<Path>{roots.workflows}/specdev/common/rules/artifact-contract.md</Path>`。
65
65
 
@@ -108,7 +108,7 @@ Archive 归档历史并将经验证知识提升为当前长期知识
108
108
  - `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`
109
109
  - `<Path>{roots.state}/specdev/changes/{change}/prototypes/</Path>`
110
110
  - `<Path>{roots.state}/specdev/changes/{change}/questionnaires/</Path>`
111
- - `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>`
111
+ - `<Path>{roots.state}/specdev/changes/{change}/eli_index.md</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/<number>_<topic>.md</Path>`
112
112
 
113
113
  ## 全局治理原则
114
114
 
@@ -197,7 +197,7 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
197
197
  | 本地 change 完成且来源可关闭 | T-triage reconcile | A |
198
198
  | 疑难 bug 或性能回归 | D-diagnose-bugs | S / T / I / R / W |
199
199
  | 模糊但可通过决策访谈收敛 | G-grill-with-docs | P / S / T / W |
200
- | 需要向五岁、零背景读者做大图少字的解释 | E-eli5 | 返回用户 / 继续当前 change |
200
+ | 需要向刚上大一、没有专业背景的读者做 Markdown 与 ASCII 图解 | E-eli5 | 返回用户 / 继续当前 change |
201
201
  | 路径超出单次上下文 | W-wayfinder | G / P / D / S / T |
202
202
  | 需要用代码回答逻辑/UI 问题 | P-prototype | G / S / T / I |
203
203
  | 固定点 diff、branch 或 PR review | C-code-review | completed / T / S / G |
@@ -216,7 +216,7 @@ Change 从 active/blocked 转为 completed 时加载 `<Path>{roots.workflows}/sp
216
216
  - **A-archive-and-consolidate** — 归档与沉淀:校验本地完成与远程 reconcile 门,复用全局归档能力移动 completed change 并提升当前知识,或从代码访谈形成可归档知识 change。
217
217
  - **C-code-review** — 代码审查:将 commit、branch、tag、merge-base 或 PR 解析为本地不可变固定点,执行隔离的标准轴与规范轴审查并持久化可恢复报告。
218
218
  - **D-diagnose-bugs** — 诊断 Bug:先建立会在精确症状上变红的紧凑反馈回路,再通过最小化、排名假设和单变量探针确认根因,输出修复契约而不实施生产修复。
219
- - **E-eli5** — 五岁解释:像对五岁的我一样解释一个主题。当用户输入 /eli5 <主题>,或要求用极其简单的图片解释某件事如何运作时,生成大图、少字的持久化 HTML 图解。
219
+ - **E-eli5** — 零基础新生解释:面向刚上大一、没有专业背景的读者解释一个主题;用 Markdown ASCII 图解说明概念、数据与调用如何流动。
220
220
  - **E-engineering-cognitive-mentor** — 工程认知导师:面向 Bug、项目源码、需求技术方案、架构设计与陌生技术领域的非执行型认知指导 Work;以证据、因果 Why、候选方案对比和逐轮澄清帮助用户形成可复述理解,并将完整问答轨迹持续持久化到当前 change。
221
221
  - **G-grill-with-docs** — 设计访谈(带文档):以完整 frontier 逐轮推进设计树,直到每个决策分支都已关闭并获得用户共识,同时持续维护当前 change 的设计树、日志、领域上下文和架构决策。
222
222
  - **I-implement** — 实现:基于 Ready Ticket 或获批小型 Spec 执行设计检查、TDD、动态派单、双轴审查、按 Goal Plan 选择的 current workspace 或 Ticket worktree 提交、直接父分支或候选合并验证和 Lead Evidence 回写。
@@ -20,7 +20,7 @@ SpecDev 通过分层工件避免同一决策被多个模型反复重做。每个
20
20
  | Evidence | `<Path>{roots.state}/specdev/changes/{change}/evidence/{ticket-id}.md</Path>` | 实际修改、命令、结果、验收映射、偏差、风险和提交引用 | 新的产品或架构决策 |
21
21
  | 代码审查 | `<Path>{roots.state}/specdev/changes/{change}/reviews/CR-###.md</Path>` | 固定点、标准轴和规范轴 finding | 实施修复或合并两轴排名 |
22
22
  | 原型记录 | `<Path>{roots.state}/specdev/changes/{change}/prototypes/{prototype-id}/record.md</Path>` | 一个问题、分支、资产、答案、promotion 和清理 | 生产实现或多个问题的计划 |
23
- | 五岁图解 | `<Path>{roots.state}/specdev/changes/{change}/eli5.html</Path>` | 面向五岁、零背景读者的大图少字解释 | 产品决定、架构决定或实现授权 |
23
+ | 零基础新生图解 | `<Path>{roots.state}/specdev/changes/{change}/eli_index.md</Path>` 与 `<Path>{roots.state}/specdev/changes/{change}/<number>_<topic>.md</Path>` | 面向刚上大一、没有专业背景读者的 Markdown 与 ASCII 图解;索引按序号持续追加 | 产品决定、架构决定或实现授权 |
24
24
  | Stakeholder 问卷 | `<Path>{roots.state}/specdev/changes/{change}/questionnaires/{slug}.md</Path>` | 第三方原始回答和恢复条件 | 未经转录确认的产品/架构决定 |
25
25
  | Wayfinder 地图 | `<Path>{roots.state}/specdev/changes/{change}/wayfinder-map.md</Path>` | 目的地、说明、已关闭决策索引、战争迷雾和范围之外 | 开放 Ticket 正文或答案详情 |
26
26
  | Wayfinder Ticket | `<Path>{roots.state}/specdev/changes/{change}/investigation/{investigation-id}.md</Path>` | 一个可精确陈述的问题、类型、阻塞和关闭状态 | 解决方案评论或交付目标 |
@@ -169,7 +169,7 @@ const STATE_ARTIFACT_BASENAMES = new Set([
169
169
  "source.md",
170
170
  "architecture-review.md",
171
171
  "architecture-review.html",
172
- "eli5.html",
172
+ "eli_index.md",
173
173
  "wayfinder-map.md",
174
174
  "design-tree.json",
175
175
  ]);
@@ -827,7 +827,7 @@ function capabilityChecks(root) {
827
827
  "eli5",
828
828
  [
829
829
  join(root, "E-eli5", "E-eli5.md"),
830
- ["五岁", "$ARGUMENTS", "大图", "少字", "eli5.html"],
830
+ ["大一新生", "零专业背景", "$ARGUMENTS", "ASCII", "eli_index.md", "{number}_{topic}.md"],
831
831
  ],
832
832
  ],
833
833
  [
@@ -1236,20 +1236,59 @@ function validatePrototypes(change, required, errors) {
1236
1236
  }
1237
1237
 
1238
1238
  function validateEli5(change, required, errors) {
1239
- const path = join(change, "eli5.html");
1240
- if (!isFile(path)) {
1241
- if (required) errors.push("eli5 stage requires eli5.html");
1239
+ const indexPath = join(change, "eli_index.md");
1240
+ const diagramFiles = readdirSync(change, { withFileTypes: true })
1241
+ .filter((entry) => entry.isFile() && /^\d{2,}_[^/\\\\\s]+\.md$/.test(entry.name))
1242
+ .map((entry) => entry.name)
1243
+ .sort();
1244
+
1245
+ if (!isFile(indexPath)) {
1246
+ if (required) errors.push("eli5 stage requires eli_index.md");
1242
1247
  return null;
1243
1248
  }
1244
1249
 
1245
- const html = readText(path);
1246
- for (const marker of ["<!doctype html", "<html", "<head", "<title", "<body"]) {
1247
- if (!html.toLowerCase().includes(marker)) errors.push(`eli5.html: missing '${marker}'`);
1250
+ const index = readText(indexPath);
1251
+ if (!index.includes("# ELI5 图解索引")) errors.push("eli_index.md: missing index heading");
1252
+ const entries = Array.from(index.matchAll(/^\|\s*(\d{2,})\s*\|\s*([^|\s]+\.md)\s*\|\s*([^|]+)\|\s*([^|]+)\|\s*$/gm));
1253
+ if (!entries.length && required) errors.push("eli_index.md: requires at least one diagram entry");
1254
+
1255
+ const indexedFiles = new Set();
1256
+ let previousNumber = 0;
1257
+ for (const entry of entries) {
1258
+ const [, number, fileName, topic, summary] = entry;
1259
+ const numericNumber = Number(number);
1260
+ if (!/^\d{2,}_[^/\\\\\s]+\.md$/.test(fileName)) {
1261
+ errors.push(`eli_index.md: invalid diagram filename '${fileName}'`);
1262
+ continue;
1263
+ }
1264
+ if (numericNumber <= previousNumber) errors.push("eli_index.md: diagram numbers must increase");
1265
+ if (numericNumber !== previousNumber + 1) errors.push("eli_index.md: diagram numbers must start at 01 and be continuous");
1266
+ previousNumber = numericNumber;
1267
+ if (!fileName.startsWith(`${number}_`)) errors.push(`eli_index.md: '${fileName}' must start with '${number}_'`);
1268
+ if (!topic.trim() || !summary.trim()) errors.push(`eli_index.md: '${fileName}' requires a topic and summary`);
1269
+ indexedFiles.add(fileName);
1248
1270
  }
1249
- if (!/<(?:img|picture|svg|canvas)\b|\brole=["']img["']/i.test(html)) {
1250
- errors.push("eli5.html: requires a picture, SVG, canvas, or element with role=img");
1271
+
1272
+ for (const fileName of diagramFiles) {
1273
+ if (!indexedFiles.has(fileName)) errors.push(`eli_index.md: missing entry for '${fileName}'`);
1274
+ }
1275
+ for (const fileName of indexedFiles) {
1276
+ if (!diagramFiles.includes(fileName)) errors.push(`eli_index.md: '${fileName}' does not exist`);
1277
+ }
1278
+
1279
+ for (const fileName of diagramFiles) {
1280
+ const markdown = readText(join(change, fileName));
1281
+ for (const heading of ["## 先看全图", "## 一步一步看", "## 术语小词典", "## 你现在能复述什么"]) {
1282
+ if (!markdown.includes(heading)) errors.push(`${fileName}: missing '${heading}'`);
1283
+ }
1284
+ if (!/```(?:text)?\s*[\s\S]*?(?:->|\||\+--)[\s\S]*?```/.test(markdown)) {
1285
+ errors.push(`${fileName}: requires an ASCII diagram in a fenced code block`);
1286
+ }
1287
+ if (/<\/?(?:html|head|body|svg|canvas|img|picture)\b/i.test(markdown)) {
1288
+ errors.push(`${fileName}: must be Markdown, not HTML`);
1289
+ }
1251
1290
  }
1252
- return path;
1291
+ return indexPath;
1253
1292
  }
1254
1293
 
1255
1294
  function validateSpec(path, errors, warnings) {