@seanyao/roll 0.5.0 → 2.602.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/CHANGELOG.md +717 -0
  2. package/LICENSE +21 -0
  3. package/README.md +65 -165
  4. package/bin/dream-test-quality-scan +110 -0
  5. package/bin/roll +14897 -815
  6. package/conventions/config.yaml +17 -1
  7. package/conventions/global/AGENTS.md +146 -100
  8. package/conventions/global/CLAUDE.md +1 -21
  9. package/conventions/global/GEMINI.md +8 -22
  10. package/conventions/global/project_rules.md +9 -0
  11. package/conventions/templates/backend-service/AGENTS.md +30 -81
  12. package/conventions/templates/backend-service/GEMINI.md +3 -3
  13. package/conventions/templates/backend-service/project_rules.md +16 -0
  14. package/conventions/templates/cli/AGENTS.md +31 -58
  15. package/conventions/templates/cli/CLAUDE.md +3 -5
  16. package/conventions/templates/cli/GEMINI.md +3 -3
  17. package/conventions/templates/cli/project_rules.md +16 -0
  18. package/conventions/templates/frontend-only/AGENTS.md +29 -64
  19. package/conventions/templates/frontend-only/GEMINI.md +3 -3
  20. package/conventions/templates/frontend-only/project_rules.md +14 -0
  21. package/conventions/templates/fullstack/AGENTS.md +31 -79
  22. package/conventions/templates/fullstack/CLAUDE.md +1 -1
  23. package/conventions/templates/fullstack/GEMINI.md +3 -3
  24. package/conventions/templates/fullstack/project_rules.md +15 -0
  25. package/lib/README.md +42 -0
  26. package/lib/__pycache__/github_sync.cpython-314.pyc +0 -0
  27. package/lib/__pycache__/loop-fmt.cpython-314.pyc +0 -0
  28. package/lib/__pycache__/loop_result_eval.cpython-314.pyc +0 -0
  29. package/lib/__pycache__/loop_unstick.cpython-314.pyc +0 -0
  30. package/lib/__pycache__/model_prices.cpython-314.pyc +0 -0
  31. package/lib/__pycache__/prices_fetcher.cpython-314.pyc +0 -0
  32. package/lib/__pycache__/roll-home.cpython-314.pyc +0 -0
  33. package/lib/__pycache__/roll-loop-status.cpython-314.pyc +0 -0
  34. package/lib/__pycache__/roll_git.cpython-314.pyc +0 -0
  35. package/lib/__pycache__/roll_render.cpython-314.pyc +0 -0
  36. package/lib/__pycache__/slides-render.cpython-314.pyc +0 -0
  37. package/lib/agent_usage/README.md +49 -0
  38. package/lib/agent_usage/__init__.py +108 -0
  39. package/lib/agent_usage/__pycache__/__init__.cpython-314.pyc +0 -0
  40. package/lib/agent_usage/__pycache__/gemini.cpython-314.pyc +0 -0
  41. package/lib/agent_usage/__pycache__/kimi.cpython-314.pyc +0 -0
  42. package/lib/agent_usage/__pycache__/openai.cpython-314.pyc +0 -0
  43. package/lib/agent_usage/__pycache__/pi.cpython-314.pyc +0 -0
  44. package/lib/agent_usage/__pycache__/pi_emit.cpython-314.pyc +0 -0
  45. package/lib/agent_usage/__pycache__/qwen.cpython-314.pyc +0 -0
  46. package/lib/agent_usage/gemini.py +127 -0
  47. package/lib/agent_usage/kimi.py +278 -0
  48. package/lib/agent_usage/kimi_emit.py +123 -0
  49. package/lib/agent_usage/openai.py +126 -0
  50. package/lib/agent_usage/pi.py +200 -0
  51. package/lib/agent_usage/pi_emit.py +135 -0
  52. package/lib/agent_usage/qwen.py +128 -0
  53. package/lib/backfill-pi-usage.py +243 -0
  54. package/lib/changelog_audit.py +155 -0
  55. package/lib/changelog_generate.py +263 -0
  56. package/lib/context_feed_budget.sh +194 -0
  57. package/lib/github_sync.py +876 -0
  58. package/lib/i18n/README.md +54 -0
  59. package/lib/i18n/agent.sh +75 -0
  60. package/lib/i18n/alert.sh +20 -0
  61. package/lib/i18n/backlog.sh +96 -0
  62. package/lib/i18n/brief.sh +5 -0
  63. package/lib/i18n/changelog.sh +5 -0
  64. package/lib/i18n/ci.sh +15 -0
  65. package/lib/i18n/debug.sh +0 -0
  66. package/lib/i18n/doctor.sh +44 -0
  67. package/lib/i18n/dream.sh +0 -0
  68. package/lib/i18n/init.sh +91 -0
  69. package/lib/i18n/lang.sh +10 -0
  70. package/lib/i18n/loop.sh +140 -0
  71. package/lib/i18n/migrate.sh +74 -0
  72. package/lib/i18n/offboard.sh +31 -0
  73. package/lib/i18n/onboard.sh +0 -0
  74. package/lib/i18n/peer.sh +41 -0
  75. package/lib/i18n/peer_help.sh +25 -0
  76. package/lib/i18n/peer_reset.sh +7 -0
  77. package/lib/i18n/peer_status.sh +5 -0
  78. package/lib/i18n/prices.sh +3 -0
  79. package/lib/i18n/prices_refresh.sh +17 -0
  80. package/lib/i18n/prices_show.sh +7 -0
  81. package/lib/i18n/propose.sh +0 -0
  82. package/lib/i18n/release.sh +0 -0
  83. package/lib/i18n/research.sh +0 -0
  84. package/lib/i18n/review_pr.sh +0 -0
  85. package/lib/i18n/sentinel.sh +0 -0
  86. package/lib/i18n/setup.sh +3 -0
  87. package/lib/i18n/shared.sh +157 -0
  88. package/lib/i18n/skills/roll-brief.sh +47 -0
  89. package/lib/i18n/skills/roll-build.sh +97 -0
  90. package/lib/i18n/skills/roll-design.sh +18 -0
  91. package/lib/i18n/skills/roll-fix.sh +53 -0
  92. package/lib/i18n/skills/roll-loop.sh +28 -0
  93. package/lib/i18n/skills/roll-onboard.sh +33 -0
  94. package/lib/i18n/skills_catalog.sh +30 -0
  95. package/lib/i18n/slides.sh +3 -0
  96. package/lib/i18n/slides_build.sh +38 -0
  97. package/lib/i18n/slides_delete.sh +19 -0
  98. package/lib/i18n/slides_list.sh +14 -0
  99. package/lib/i18n/slides_logs.sh +12 -0
  100. package/lib/i18n/slides_new.sh +15 -0
  101. package/lib/i18n/slides_preview.sh +14 -0
  102. package/lib/i18n/slides_templates.sh +7 -0
  103. package/lib/i18n/status.sh +21 -0
  104. package/lib/i18n/update.sh +24 -0
  105. package/lib/i18n.sh +211 -0
  106. package/lib/loop-exit-summary.py +393 -0
  107. package/lib/loop-fmt.py +589 -0
  108. package/lib/loop_pick_agent.py +316 -0
  109. package/lib/loop_result_eval.py +469 -0
  110. package/lib/loop_unstick.py +180 -0
  111. package/lib/model_prices.py +186 -0
  112. package/lib/prices/README.md +35 -0
  113. package/lib/prices/snapshot-2026-05-22.json +22 -0
  114. package/lib/prices/snapshot-2026-05-23-deepseek.json +15 -0
  115. package/lib/prices/snapshot-2026-05-23-kimi.json +14 -0
  116. package/lib/prices_fetcher.py +285 -0
  117. package/lib/roll-backlog.py +225 -0
  118. package/lib/roll-brief.py +286 -0
  119. package/lib/roll-help.py +158 -0
  120. package/lib/roll-home.py +556 -0
  121. package/lib/roll-init.py +156 -0
  122. package/lib/roll-loop-status.py +1683 -0
  123. package/lib/roll-loop-story.py +191 -0
  124. package/lib/roll-onboard-render.py +378 -0
  125. package/lib/roll-peer.py +252 -0
  126. package/lib/roll-plan-validate.py +386 -0
  127. package/lib/roll-setup.py +102 -0
  128. package/lib/roll-status.py +367 -0
  129. package/lib/roll_git.py +41 -0
  130. package/lib/roll_render.py +414 -0
  131. package/lib/slides/components/README.md +123 -0
  132. package/lib/slides/components/cards-2.html +9 -0
  133. package/lib/slides/components/cards-3.html +9 -0
  134. package/lib/slides/components/cards-4.html +9 -0
  135. package/lib/slides/components/compare.html +22 -0
  136. package/lib/slides/components/highlight.html +9 -0
  137. package/lib/slides/components/pipeline.html +12 -0
  138. package/lib/slides/components/plain.html +7 -0
  139. package/lib/slides/components/quote.html +4 -0
  140. package/lib/slides/components/timeline.html +9 -0
  141. package/lib/slides/templates/introduction-v3.html +571 -0
  142. package/lib/slides/templates/pitch.html +0 -0
  143. package/lib/slides-render.py +778 -0
  144. package/lib/slides-validate.py +357 -0
  145. package/lib/test_quality_gate.py +143 -0
  146. package/package.json +8 -7
  147. package/skills/roll-.changelog/SKILL.md +406 -33
  148. package/skills/roll-.clarify/SKILL.md +5 -2
  149. package/skills/roll-.dream/SKILL.md +374 -0
  150. package/skills/roll-.echo/SKILL.md +5 -2
  151. package/skills/roll-.qa/SKILL.md +57 -3
  152. package/skills/roll-.review/SKILL.md +42 -3
  153. package/skills/roll-brief/SKILL.md +209 -0
  154. package/skills/roll-build/SKILL.md +308 -63
  155. package/skills/roll-debug/SKILL.md +341 -162
  156. package/skills/roll-debug/injectable-bb.js +263 -0
  157. package/skills/roll-deck/SKILL.md +296 -0
  158. package/skills/roll-design/ENGINEERING_CHECKLIST.md +1 -1
  159. package/skills/roll-design/SKILL.md +727 -94
  160. package/skills/roll-doc/SKILL.md +595 -0
  161. package/skills/roll-doctor/SKILL.md +192 -0
  162. package/skills/roll-fix/SKILL.md +149 -32
  163. package/skills/{roll-jot → roll-idea}/SKILL.md +18 -10
  164. package/skills/roll-loop/SKILL.md +578 -0
  165. package/skills/roll-notes/SKILL.md +103 -0
  166. package/skills/roll-onboard/SKILL.md +234 -0
  167. package/skills/roll-peer/SKILL.md +336 -0
  168. package/skills/roll-propose/SKILL.md +157 -0
  169. package/skills/roll-review-pr/SKILL.md +58 -0
  170. package/skills/roll-sentinel/SKILL.md +11 -2
  171. package/skills/roll-spar/SKILL.md +8 -6
  172. package/template/.github/workflows/ci.yml +5 -2
  173. package/template/AGENTS.md +20 -74
  174. package/skills/roll-research/SKILL.md +0 -307
  175. package/skills/roll-research/references/schema.json +0 -162
  176. package/skills/roll-research/scripts/md_to_pdf.py +0 -289
  177. package/tools/roll-fetch/SKILL.md +0 -182
  178. package/tools/roll-fetch/package.json +0 -15
  179. package/tools/roll-fetch/smart-web-fetch.js +0 -558
  180. package/tools/roll-probe/SKILL.md +0 -84
  181. /package/template/{BACKLOG.md → .roll/backlog.md} +0 -0
@@ -0,0 +1,263 @@
1
+ // Roll Debug — Injectable BB Diagnostic Stub
2
+ // Injected into page context by Playwright when native BB is absent.
3
+ // Exposes window.__BB_DATA__ and [data-testid="bb-toggle"] for unified collection.
4
+ // Fully unmountable via window.__BB_UNMOUNT__().
5
+
6
+ (function () {
7
+ 'use strict';
8
+
9
+ if (window.__BB_DATA__) return; // Already mounted
10
+
11
+ // ─── Backup originals ───
12
+ const _orig = {
13
+ console: {},
14
+ fetch: window.fetch,
15
+ XHR_open: XMLHttpRequest.prototype.open,
16
+ XHR_send: XMLHttpRequest.prototype.send,
17
+ };
18
+ ['error', 'warn', 'log', 'info'].forEach((m) => {
19
+ _orig.console[m] = console[m];
20
+ });
21
+
22
+ // ─── BB State ───
23
+ const BB = {
24
+ version: 'stub-1.0',
25
+ mountedAt: Date.now(),
26
+ console: { errors: [], warnings: [], logs: [] },
27
+ network: { failed: [], slow: [], all: [] },
28
+ errors: [],
29
+ dom: {},
30
+ performance: {},
31
+ };
32
+
33
+ // ─── Console hooks (with internal error firewall) ───
34
+ ['error', 'warn', 'log', 'info'].forEach((m) => {
35
+ const key = m === 'error' ? 'errors' : m === 'warn' ? 'warnings' : 'logs';
36
+ const orig = _orig.console[m];
37
+ console[m] = function bbHookedConsole(...args) {
38
+ try {
39
+ BB.console[key].push({
40
+ message: args
41
+ .map((a) => {
42
+ try {
43
+ return typeof a === 'object' ? JSON.stringify(a) : String(a);
44
+ } catch (e) {
45
+ return '[unstringifiable]';
46
+ }
47
+ })
48
+ .join(' '),
49
+ timestamp: Date.now(),
50
+ });
51
+ } catch (e) {
52
+ /* swallow stub internal error */
53
+ }
54
+ return orig.apply(this, args);
55
+ };
56
+ });
57
+
58
+ // ─── Fetch hook (transparent wrapper) ───
59
+ const origFetch = _orig.fetch;
60
+ window.fetch = function bbHookedFetch(...args) {
61
+ const start = Date.now();
62
+ const url =
63
+ typeof args[0] === 'string'
64
+ ? args[0]
65
+ : args[0]?.url || '[unknown]';
66
+ const method = args[1]?.method || 'GET';
67
+
68
+ return origFetch.apply(this, args).then(
69
+ (res) => {
70
+ try {
71
+ const duration = Date.now() - start;
72
+ const entry = { url, status: res.status, duration, method };
73
+ BB.network.all.push(entry);
74
+ if (!res.ok) BB.network.failed.push(entry);
75
+ if (duration > 3000) BB.network.slow.push(entry);
76
+ } catch (e) {
77
+ /* swallow */
78
+ }
79
+ return res;
80
+ },
81
+ (err) => {
82
+ try {
83
+ BB.network.failed.push({
84
+ url,
85
+ error: err.message,
86
+ duration: Date.now() - start,
87
+ method,
88
+ });
89
+ } catch (e) {
90
+ /* swallow */
91
+ }
92
+ throw err;
93
+ }
94
+ );
95
+ };
96
+ try {
97
+ window.fetch.toString = () => 'function fetch() { [native code] }';
98
+ } catch (e) {
99
+ /* ignore */
100
+ }
101
+
102
+ // ─── XHR hook ───
103
+ XMLHttpRequest.prototype.open = function bbHookedOpen(method, url, ...rest) {
104
+ this._bb = { method, url: String(url), start: null };
105
+ return _orig.XHR_open.call(this, method, url, ...rest);
106
+ };
107
+
108
+ XMLHttpRequest.prototype.send = function bbHookedSend(...args) {
109
+ if (this._bb) this._bb.start = Date.now();
110
+ const handler = () => {
111
+ if (!this._bb) return;
112
+ try {
113
+ const duration = Date.now() - this._bb.start;
114
+ const entry = {
115
+ url: this._bb.url,
116
+ status: this.status,
117
+ duration,
118
+ method: this._bb.method,
119
+ };
120
+ BB.network.all.push(entry);
121
+ if (this.status >= 400 || this.status === 0)
122
+ BB.network.failed.push(entry);
123
+ if (duration > 3000) BB.network.slow.push(entry);
124
+ } catch (e) {
125
+ /* swallow */
126
+ }
127
+ };
128
+ this.addEventListener('loadend', handler, { once: true });
129
+ return _orig.XHR_send.apply(this, args);
130
+ };
131
+
132
+ // ─── JS Error listeners ───
133
+ const onError = (e) => {
134
+ try {
135
+ BB.errors.push({
136
+ message: e.message,
137
+ stack: e.error?.stack,
138
+ timestamp: Date.now(),
139
+ });
140
+ } catch (e) {
141
+ /* swallow */
142
+ }
143
+ };
144
+ const onRejection = (e) => {
145
+ try {
146
+ BB.errors.push({
147
+ message: e.reason?.message || String(e.reason),
148
+ stack: e.reason?.stack,
149
+ timestamp: Date.now(),
150
+ });
151
+ } catch (e) {
152
+ /* swallow */
153
+ }
154
+ };
155
+ window.addEventListener('error', onError);
156
+ window.addEventListener('unhandledrejection', onRejection);
157
+
158
+ // ─── Performance ───
159
+ const capturePerf = () => {
160
+ try {
161
+ const nav = performance.getEntriesByType('navigation')[0];
162
+ BB.performance = {
163
+ domContentLoaded: nav?.domContentLoadedEventEnd,
164
+ loadComplete: nav?.loadEventEnd,
165
+ firstContentfulPaint:
166
+ performance.getEntriesByName('first-contentful-paint')[0]?.startTime,
167
+ largestContentfulPaint: performance
168
+ .getEntriesByType('largest-contentful-paint')
169
+ .pop()?.startTime,
170
+ };
171
+ } catch (e) {
172
+ /* swallow */
173
+ }
174
+ };
175
+ if (document.readyState === 'complete') {
176
+ capturePerf();
177
+ } else {
178
+ window.addEventListener('load', capturePerf, { once: true });
179
+ }
180
+
181
+ // ─── DOM Capture ───
182
+ function captureDOM() {
183
+ try {
184
+ const info = (sel) => {
185
+ const el = document.querySelector(sel);
186
+ return el
187
+ ? {
188
+ exists: true,
189
+ visible: el.offsetParent !== null,
190
+ text: el.textContent?.slice(0, 200),
191
+ }
192
+ : { exists: false };
193
+ };
194
+ return {
195
+ title: document.title,
196
+ url: location.href,
197
+ htmlLength: document.documentElement.innerHTML.length,
198
+ keyElements: {
199
+ '#root': info('#root'),
200
+ '#app': info('#app'),
201
+ '[data-testid="error"]': info('[data-testid="error"]'),
202
+ '.error': info('.error'),
203
+ '.loading': info('.loading'),
204
+ },
205
+ };
206
+ } catch (e) {
207
+ return { error: 'DOM capture failed', url: location.href };
208
+ }
209
+ }
210
+
211
+ // ─── Public API ───
212
+ BB.getData = () => ({ ...BB, dom: captureDOM(), collectedAt: Date.now() });
213
+ window.__BB_DATA__ = BB;
214
+
215
+ // ─── Visible BB toggle button ───
216
+ let btn;
217
+ if (document.body) {
218
+ btn = document.createElement('button');
219
+ btn.dataset.testid = 'bb-toggle';
220
+ btn.textContent = 'BB';
221
+ btn.title = 'Black Box Diagnostic Probe — click to download report';
222
+ btn.style.cssText =
223
+ 'position:fixed;bottom:12px;right:12px;z-index:99999;' +
224
+ 'width:36px;height:36px;border-radius:50%;border:none;' +
225
+ 'background:#ff4444;color:#fff;font-size:11px;font-weight:bold;' +
226
+ 'font-family:sans-serif;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,0.3);' +
227
+ 'display:flex;align-items:center;justify-content:center;' +
228
+ 'opacity:0.85;transition:opacity 0.2s;';
229
+ btn.onmouseenter = () => (btn.style.opacity = '1');
230
+ btn.onmouseleave = () => (btn.style.opacity = '0.85');
231
+ btn.onclick = () => {
232
+ const data = BB.getData();
233
+ const blob = new Blob([JSON.stringify(data, null, 2)], {
234
+ type: 'application/json',
235
+ });
236
+ const a = document.createElement('a');
237
+ a.href = URL.createObjectURL(blob);
238
+ a.download = `bb-diagnostic-${Date.now()}.json`;
239
+ a.click();
240
+ };
241
+ document.body.appendChild(btn);
242
+ }
243
+
244
+ // ─── Unmount (restore page to original state) ───
245
+ window.__BB_UNMOUNT__ = function () {
246
+ try {
247
+ ['error', 'warn', 'log', 'info'].forEach(
248
+ (m) => (console[m] = _orig.console[m])
249
+ );
250
+ window.fetch = _orig.fetch;
251
+ XMLHttpRequest.prototype.open = _orig.XHR_open;
252
+ XMLHttpRequest.prototype.send = _orig.XHR_send;
253
+ window.removeEventListener('error', onError);
254
+ window.removeEventListener('unhandledrejection', onRejection);
255
+ if (btn) btn.remove();
256
+ delete window.__BB_DATA__;
257
+ delete window.__BB_UNMOUNT__;
258
+ return true;
259
+ } catch (e) {
260
+ return false;
261
+ }
262
+ };
263
+ })();
@@ -0,0 +1,296 @@
1
+ ---
2
+ name: roll-deck
3
+ license: MIT
4
+ allowed-tools: "Read, Edit, Write, Glob, Grep, Bash(git:*)"
5
+ description: "Generate a bilingual 18-slide deck.md from a topic. Reads the current project (README, AGENTS.md, backlog, features), discusses outline with the user when needed, and writes one file: .roll/slides/<slug>/deck.md. Each slide carries title_en/title_zh + body_en/body_zh + evidence (file:line). HTML rendering is a separate bash step (roll slides build)."
6
+ ---
7
+
8
+ # roll-deck
9
+
10
+ > Topic in, deck.md out. AI authoring layer of the slide-deck pipeline.
11
+ > 主题进,deck.md 出。幻灯片管线的 AI 创作层。
12
+
13
+ ## Trigger
14
+
15
+ User invokes `roll-deck` from the CLI:
16
+
17
+ ```
18
+ $roll-deck "Introducing Roll Loop"
19
+ $roll-deck "How TCR keeps us honest"
20
+ ```
21
+
22
+ `roll slides new "<topic>"` shells out to the selected agent with this skill loaded.
23
+ `roll slides new "<topic>"` 会通过所选 agent 加载本 skill。
24
+
25
+ ## When Not to Use
26
+
27
+ - Rendering an existing `deck.md` to HTML → use `roll slides build <slug>` (bash, no AI).
28
+ - Listing or previewing decks → use `roll slides list` / `roll slides preview <slug>`.
29
+ - Authoring backlog stories → use `$roll-design` / `$roll-idea`.
30
+
31
+ ## Hard Constraints 硬约束
32
+
33
+ - **You may write exactly one file**: `.roll/slides/<slug>/deck.md`.
34
+ - You MUST NOT edit any other file: no README, no AGENTS.md, no backlog, no source code, no `.roll/slides/*.html`.
35
+ - HTML rendering is `roll slides build <slug>` — never produce HTML here.
36
+ - If `.roll/slides/<slug>/deck.md` already exists, ask the user before overwriting.
37
+ - **Layout must come from the whitelist**: `plain`, `cards-2`, `cards-3`, `cards-4`, `compare`, `pipeline`, `timeline`, `quote`, `highlight`. Inventing a layout name makes `roll slides build` fail with `Unknown layout`.
38
+ **layout 必须从白名单选**:`plain` / `cards-2` / `cards-3` / `cards-4` / `compare` / `pipeline` / `timeline` / `quote` / `highlight`。自创 layout 名渲染会失败。
39
+
40
+ ## Inputs
41
+
42
+ - `<topic>`: a free-text topic string (required).
43
+ - `<template>`: template name, default `introduction-v3`.
44
+ - `<slug>`: kebab-case slug derived from the topic by the CLI; you receive it.
45
+
46
+ ## Workflow
47
+
48
+ ### 1. Read the project 阅读项目
49
+
50
+ Read in this order, skipping files that don't exist:
51
+
52
+ 0. `package.json` — **project identity**: extract `name`, `homepage`, `repository.url`, `author`. These are hard facts that MUST NOT be guessed or inferred from memory.
53
+ `package.json` — **项目身份**: 提取 `name`、`homepage`、`repository.url`、`author`。这些是硬事实,禁止猜测。
54
+ 1. `README.md` — top-level pitch and entry points.
55
+ 2. `AGENTS.md` — communication style, conventions, where to look.
56
+ 3. `.roll/backlog.md` — recently Done Stories and the top of the Todo queue.
57
+ 4. `.roll/features/**/*.md` — feature specs relevant to the topic.
58
+ 5. Targeted `Grep` for the topic keywords across the repo (≤ 30 hits).
59
+
60
+ Stop reading when you have enough to write 18 slides with concrete evidence.
61
+ 拿到足够 18 张 slide 的证据就停。
62
+
63
+ ### 2. Outline check outline 校验
64
+
65
+ - If the topic is unambiguous and the project gives clear evidence (high confidence), proceed directly.
66
+ - If the topic is vague (multiple valid framings), restate the proposed 18-slide outline in 3–5 lines and ask the user to confirm or adjust before writing. Wait for confirmation.
67
+ - Never ask more than one round of questions — pick the strongest framing and proceed.
68
+
69
+ ### 3. Generate 18 slides 生成 18 张 slide
70
+
71
+ Default count is `18` (or the count the template prescribes). Each slide MUST contain:
72
+
73
+ - `layout` — one of the whitelist layouts (see "Layout 选择手册" below). **You MUST declare `layout:` explicitly on every slide, before `evidence:`** — this forces a deliberate choice and stops every slide collapsing to `plain`.
74
+ - `title_en` — short English title (≤ 8 words).
75
+ - `title_zh` — short Chinese title (≤ 16 chars).
76
+ - `body_en` — markdown body, concise, ≤ 200 words.
77
+ - `body_zh` — Chinese body, concise, ≤ 200 chars.
78
+ - `evidence` — list of `<path>:<line>` references that ground the claim.
79
+
80
+ **Grounding rules** (two tiers):
81
+
82
+ - **Hard facts** (URLs, package names, version numbers, person names, quotes with attribution): MUST cite the source file and line (e.g. `package.json:2`, `README.md:15`). If no source can be found, mark the claim as `⚠️ unverified` — never guess.
83
+ - **Narrative / opinions**: every 3 consecutive slides MUST contain at least 1 evidence citation. If you cannot ground a slide, label it `⚠️ unverified` and explain why in one line.
84
+
85
+ **Grounding 规则**(两级):
86
+
87
+ - **硬事实**(URL、包名、版本号、人名、带归属的引言):MUST 引用源文件及行号(如 `package.json:2`)。找不到来源则标 `⚠️ unverified`——禁止猜测。
88
+ - **叙述/观点**:每 3 张 slide 至少 1 条 evidence。无法取证时打 `⚠️ unverified` 并一行说明。
89
+
90
+ Bilingual rule: English and Chinese MUST be on separate lines in the rendered body — never inline on the same line.
91
+
92
+ ## Layout 选择手册 Layout Selection Playbook
93
+
94
+ Pick the layout from the **shape of the content**, not from a wish to look fancy.
95
+ 按**内容形态**选 layout,而不是为了好看硬凑。
96
+
97
+ ### Decision matrix 决策矩阵
98
+
99
+ | Content shape 内容形态 | Pick 推荐 layout | Anti-pattern 反例(不要用) |
100
+ |---|---|---|
101
+ | Before/after, old vs new, "what we did vs didn't" 前后对比 / 旧 vs 新 | `compare` | `cards-2` — loses the contrast semantics 缺失对比语义 |
102
+ | Multi-step process, pipeline, staged flow 多步骤流程 / 阶段流转 | `pipeline` | `cards-N` — order is invisible 看不出顺序 |
103
+ | Time series, evolution, changelog 时间序列 / 演进 / changelog | `timeline` | `pipeline` — pipeline = steps, timeline = time pipeline 表步骤、timeline 表时间 |
104
+ | 2/3/4 parallel concepts, no internal order 2/3/4 个并列概念,无顺序 | `cards-2` / `cards-3` / `cards-4` | ≥5 items crammed in — split the slide ≥5 项硬塞,请拆 slide |
105
+ | A line, a testimonial, the user's own words 引言 / 金句 / 用户原话 | `quote` | `highlight` — quote has attribution, highlight is a conclusion quote 有归属,highlight 是结论 |
106
+ | The one key takeaway / one-line conclusion 关键结论 / 一句话总结 | `highlight` | `plain` — drowns in the paragraph 淹没在段落里 |
107
+ | Ordinary prose, explanation, plain list 普通段落 / 解释 / 列表 | `plain` | — |
108
+
109
+ **At most one layout per slide.** Do not stack layouts. And do not force a rich
110
+ component when the content is genuinely just a paragraph — **if the content is
111
+ really one block of prose, `plain` is the correct choice**, not a failure.
112
+ **每张 slide 最多 1 个 layout。** 不要为了用富组件硬凑;内容真就是一段话时,`plain` 是正确答案,不是偷懒。
113
+
114
+ ### Worked examples 真实示例
115
+
116
+ Five examples, drawn from real `site/slides/roll-introduction-v5.html` slides.
117
+ 五个示例,取自 v5 实际 slide。
118
+
119
+ **1. "TCR before vs after" → `compare`**
120
+ 内容是"用 TCR 之前 vs 之后" → 选 `compare`:
121
+
122
+ ```markdown
123
+ ## Slide 4
124
+ layout: compare
125
+ title_en: "Why TCR"
126
+ title_zh: "为什么用 TCR"
127
+ left_title_en: "Before"
128
+ left_title_zh: "之前"
129
+ right_title_en: "After"
130
+ right_title_zh: "之后"
131
+ left_items:
132
+ - text_en: "Broken commits land on main"
133
+ text_zh: "坏提交直接进 main"
134
+ right_items:
135
+ - text_en: "Every commit is green or reverted"
136
+ text_zh: "每个提交要么绿要么回滚"
137
+ evidence:
138
+ - AGENTS.md:42
139
+ ```
140
+
141
+ **2. "The Roll loop pipeline" → `pipeline`**
142
+ 内容是"idea → backlog → build → verify → release 流转" → 选 `pipeline`:
143
+
144
+ ```markdown
145
+ ## Slide 7
146
+ layout: pipeline
147
+ title_en: "The Roll Loop"
148
+ title_zh: "Roll 循环"
149
+ stages:
150
+ - title_en: "Idea"
151
+ title_zh: "想法"
152
+ desc_en: "Capture in backlog"
153
+ desc_zh: "落到 backlog"
154
+ css_class: "pipe-idea"
155
+ - title_en: "Build"
156
+ title_zh: "构建"
157
+ desc_en: "TCR micro-commits"
158
+ desc_zh: "TCR 微提交"
159
+ css_class: "pipe-build"
160
+ evidence:
161
+ - skills/roll-loop/SKILL.md:1
162
+ ```
163
+
164
+ **3. "How Roll grew over releases" → `timeline`**
165
+ 内容是"v1 → v2 → 现在的演进" → 选 `timeline`:
166
+
167
+ ```markdown
168
+ ## Slide 12
169
+ layout: timeline
170
+ title_en: "How Roll Grew"
171
+ title_zh: "Roll 的演进"
172
+ items:
173
+ - title_en: "First loop"
174
+ title_zh: "第一版 loop"
175
+ body_en: "Hourly cron executor."
176
+ body_zh: "每小时 cron 执行器。"
177
+ evidence:
178
+ - CHANGELOG.md:1
179
+ ```
180
+
181
+ **4. "Three pillars of Roll" → `cards-3`**
182
+ 内容是"三个并列支柱,无先后" → 选 `cards-3`:
183
+
184
+ ```markdown
185
+ ## Slide 5
186
+ layout: cards-3
187
+ title_en: "Three Pillars"
188
+ title_zh: "三大支柱"
189
+ cards:
190
+ - title_en: "Skills"
191
+ title_zh: "技能"
192
+ body_en: "Composable AI workflows."
193
+ body_zh: "可组合的 AI 工作流。"
194
+ - title_en: "Loop"
195
+ title_zh: "循环"
196
+ body_en: "Autonomous backlog executor."
197
+ body_zh: "自主 backlog 执行器。"
198
+ - title_en: "TCR"
199
+ title_zh: "TCR"
200
+ body_en: "Test && commit || revert."
201
+ body_zh: "测试通过则提交,否则回滚。"
202
+ evidence:
203
+ - README.md:1
204
+ ```
205
+
206
+ **5. "Kimi's verdict" → `quote`**
207
+ 内容是带归属的一句用户原话 → 选 `quote`:
208
+
209
+ ```markdown
210
+ ## Slide 16
211
+ layout: quote
212
+ title_en: "Peer Verdict"
213
+ title_zh: "评审结论"
214
+ text_en: "AGREE with refinement."
215
+ text_zh: "同意,附细化意见。"
216
+ evidence:
217
+ - .roll/features/authoring/slide-deck-generator.md:919
218
+ ```
219
+
220
+ Whitelist field names match `lib/slides/components/README.md` — copy them
221
+ verbatim (`left_items` / `right_items` / `stages[].css_class` / `text_en` …).
222
+ 字段名以 `lib/slides/components/README.md` 为准,原样照抄。
223
+
224
+ ## Known agent limitations 已知 agent 局限
225
+
226
+ The layout playbook is loadable by any agent (mechanism is agent-agnostic), but
227
+ whether the model actually *applies* the decision matrix scales with model
228
+ strength. Claude Opus / Sonnet are the most reliable. If an agent degrades to
229
+ "all `plain` placeholders" and ignores the matrix, note it here rather than
230
+ blocking — quality, not mechanism, is the variable.
231
+ layout 手册任何 agent 都读得到(机制 agnostic),但是否真按矩阵挑 layout 跟模型强度相关。Claude Opus / Sonnet 最稳;某 agent 退化成全 plain 时记到此处,不阻塞。
232
+
233
+ - (No degradations recorded yet. 暂无记录。)
234
+
235
+ ### 4. Write deck.md 写文件
236
+
237
+ Write to `.roll/slides/<slug>/deck.md` with this structure:
238
+
239
+ ```markdown
240
+ ---
241
+ template: <template>
242
+ slug: <slug>
243
+ title_en: "<topic in English>"
244
+ title_zh: "<topic in Chinese>"
245
+ total_slides: 18
246
+ created: <YYYY-MM-DD>
247
+ pkg_name: "<from package.json name>"
248
+ repo_url: "<from package.json repository.url>"
249
+ site_url: "<from package.json homepage>"
250
+ author: "<from package.json author>"
251
+ ---
252
+
253
+ ## Slide 1
254
+ layout: plain
255
+ title_en: "..."
256
+ title_zh: "..."
257
+ body_en: |
258
+ ...
259
+ body_zh: |
260
+ ...
261
+ evidence:
262
+ - README.md:12
263
+ - .roll/backlog.md:34
264
+
265
+ ## Slide 2
266
+ ...
267
+ ```
268
+
269
+ Every slide declares `layout:` first (see "Layout 选择手册"); rich layouts add
270
+ their own structured fields (e.g. `cards`, `left_items`, `stages`) in place of
271
+ `body_en` / `body_zh`.
272
+ 每张 slide 先声明 `layout:`;富 layout 用各自的结构化字段取代 `body_en` / `body_zh`。
273
+
274
+ `total_slides` MUST match the number of `## Slide N` blocks. The validator (run by `roll slides build`) will reject mismatches.
275
+
276
+ Project identity fields (`pkg_name`, `repo_url`, `site_url`, `author`) are copied verbatim from `package.json` — never infer or guess these values. `roll slides build` injects them into the HTML template (cover, back cover, footer).
277
+ 项目身份字段从 `package.json` 原样复制——禁止推测。`roll slides build` 会把它们注入 HTML 模板(封面、封底、页脚)。
278
+
279
+ ### 5. Stop after writing 写完即停
280
+
281
+ Once `deck.md` is written, stop. Do not run `roll slides build` yourself — that
282
+ is a deliberate human gate. The CLI prints the bilingual "Next" hint after the
283
+ agent exits, so the agent should not duplicate it.
284
+
285
+ ## Output format expectations
286
+
287
+ - One file written: `.roll/slides/<slug>/deck.md`.
288
+ - No HTML, no edits to any other file.
289
+ - No "Next" hint in the agent's final message (the CLI prints it).
290
+
291
+ ## Rules
292
+
293
+ - Honour the hard constraints above. The CLI will trust you not to scribble outside the deck file.
294
+ - If `.roll/` does not exist, create it first (with `mkdir -p .roll/slides/<slug>`).
295
+ - If the project has no `README.md` or `AGENTS.md`, proceed using what is available and flag affected slides as `⚠️ unverified`.
296
+ - Keep slides terse — this is a deck, not a doc.
@@ -1,4 +1,4 @@
1
- # Wukong Engineering Common Sense Checklist
1
+ # Roll Engineering Common Sense Checklist
2
2
 
3
3
  > **These are not best practices — they are baseline requirements.** Violations are bugs.
4
4