@drunkcoding/agents-and-skills 0.0.44 → 0.0.46

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 (107) hide show
  1. package/.claude-plugin/marketplace.json +2 -47
  2. package/README.md +3 -6
  3. package/package.json +4 -1
  4. package/plugins/multica-tool/.claude-plugin/plugin.json +1 -1
  5. package/plugins/multica-tool/scripts/lib.mjs +53 -4
  6. package/plugins/multica-tool/scripts/multica-export.mjs +170 -50
  7. package/plugins/multica-tool/scripts/multica-import.mjs +209 -27
  8. package/plugins/multica-tool/skills/export/SKILL.md +91 -22
  9. package/plugins/multica-tool/skills/import/SKILL.md +24 -9
  10. package/plugins/multica-tool/skills/sync/SKILL.md +1 -1
  11. package/plugins/plugin-validator/.claude-plugin/plugin.json +1 -1
  12. package/plugins/html-effectiveness/.claude-plugin/plugin.json +0 -17
  13. package/plugins/html-effectiveness/README.md +0 -28
  14. package/plugins/html-effectiveness/agents/report-builder.md +0 -66
  15. package/plugins/html-effectiveness/assets/base.css +0 -51
  16. package/plugins/html-effectiveness/assets/base.js +0 -11
  17. package/plugins/html-effectiveness/assets/charts.js +0 -1
  18. package/plugins/html-effectiveness/assets/components.css +0 -10
  19. package/plugins/html-effectiveness/commands/html-report.md +0 -13
  20. package/plugins/html-effectiveness/docs/template-gallery.md +0 -28
  21. package/plugins/html-effectiveness/package.json +0 -6
  22. package/plugins/html-effectiveness/scripts/_tmp.js +0 -37
  23. package/plugins/html-effectiveness/scripts/catalog.js +0 -47
  24. package/plugins/html-effectiveness/scripts/extract.js +0 -104
  25. package/plugins/html-effectiveness/scripts/mustache.js +0 -90
  26. package/plugins/html-effectiveness/scripts/render.js +0 -176
  27. package/plugins/html-effectiveness/skills/html-effectiveness/SKILL.md +0 -94
  28. package/plugins/html-effectiveness/templates/01-exploration-code-approaches.html.tmpl +0 -400
  29. package/plugins/html-effectiveness/templates/02-exploration-visual-designs.html.tmpl +0 -456
  30. package/plugins/html-effectiveness/templates/03-code-review-pr.html.tmpl +0 -581
  31. package/plugins/html-effectiveness/templates/04-code-understanding.html.tmpl +0 -443
  32. package/plugins/html-effectiveness/templates/05-design-system.html.tmpl +0 -578
  33. package/plugins/html-effectiveness/templates/06-component-variants.html.tmpl +0 -557
  34. package/plugins/html-effectiveness/templates/07-prototype-animation.html.tmpl +0 -417
  35. package/plugins/html-effectiveness/templates/08-prototype-interaction.html.tmpl +0 -363
  36. package/plugins/html-effectiveness/templates/09-slide-deck.html.tmpl +0 -535
  37. package/plugins/html-effectiveness/templates/10-svg-illustrations.html.tmpl +0 -444
  38. package/plugins/html-effectiveness/templates/11-status-report.html.tmpl +0 -152
  39. package/plugins/html-effectiveness/templates/12-incident-report.html.tmpl +0 -547
  40. package/plugins/html-effectiveness/templates/13-flowchart-diagram.html.tmpl +0 -361
  41. package/plugins/html-effectiveness/templates/14-research-feature-explainer.html.tmpl +0 -348
  42. package/plugins/html-effectiveness/templates/15-research-concept-explainer.html.tmpl +0 -334
  43. package/plugins/html-effectiveness/templates/16-implementation-plan.html.tmpl +0 -657
  44. package/plugins/html-effectiveness/templates/17-pr-writeup.html.tmpl +0 -553
  45. package/plugins/html-effectiveness/templates/18-editor-triage-board.html.tmpl +0 -541
  46. package/plugins/html-effectiveness/templates/19-editor-feature-flags.html.tmpl +0 -627
  47. package/plugins/html-effectiveness/templates/20-editor-prompt-tuner.html.tmpl +0 -687
  48. package/plugins/html-effectiveness/templates/manifest.json +0 -441
  49. package/plugins/team-share/.claude-plugin/plugin.json +0 -18
  50. package/plugins/team-share/README.md +0 -46
  51. package/plugins/team-share/agents/team-share.md +0 -53
  52. package/plugins/team-share/commands/team-share.md +0 -4
  53. package/plugins/team-share/skills/claude-config/SKILL.md +0 -143
  54. package/plugins/team-share/skills/codegraph-setup/SKILL.md +0 -81
  55. package/plugins/team-share/skills/understand-setup/SKILL.md +0 -115
  56. package/plugins/tech-graph/.claude-plugin/plugin.json +0 -17
  57. package/plugins/tech-graph/README.md +0 -66
  58. package/plugins/tech-graph/agents/tech-graph.md +0 -97
  59. package/plugins/tech-graph/commands/tech-graph.md +0 -13
  60. package/plugins/tech-graph/scripts/check-deps.sh +0 -55
  61. package/plugins/tech-graph/skills/tech-graph/LICENSE +0 -21
  62. package/plugins/tech-graph/skills/tech-graph/README.md +0 -555
  63. package/plugins/tech-graph/skills/tech-graph/README.zh.md +0 -514
  64. package/plugins/tech-graph/skills/tech-graph/SKILL.md +0 -263
  65. package/plugins/tech-graph/skills/tech-graph/agents/openai.yaml +0 -4
  66. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style1-flat.png +0 -0
  67. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style2-dark.png +0 -0
  68. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style3-blueprint.png +0 -0
  69. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style4-notion.png +0 -0
  70. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style5-glass.png +0 -0
  71. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style6-claude.png +0 -0
  72. package/plugins/tech-graph/skills/tech-graph/assets/samples/sample-style7-openai.png +0 -0
  73. package/plugins/tech-graph/skills/tech-graph/fixtures/agent-memory-types-style4.json +0 -181
  74. package/plugins/tech-graph/skills/tech-graph/fixtures/api-flow-style7.json +0 -40
  75. package/plugins/tech-graph/skills/tech-graph/fixtures/mem0-style1.json +0 -297
  76. package/plugins/tech-graph/skills/tech-graph/fixtures/microservices-style3.json +0 -64
  77. package/plugins/tech-graph/skills/tech-graph/fixtures/multi-agent-style5.json +0 -45
  78. package/plugins/tech-graph/skills/tech-graph/fixtures/system-architecture-style6.json +0 -48
  79. package/plugins/tech-graph/skills/tech-graph/fixtures/tool-call-style2.json +0 -182
  80. package/plugins/tech-graph/skills/tech-graph/package.json +0 -42
  81. package/plugins/tech-graph/skills/tech-graph/references/diagram-types.md +0 -171
  82. package/plugins/tech-graph/skills/tech-graph/references/icons.md +0 -406
  83. package/plugins/tech-graph/skills/tech-graph/references/style-1-flat-icon.md +0 -108
  84. package/plugins/tech-graph/skills/tech-graph/references/style-2-dark-terminal.md +0 -107
  85. package/plugins/tech-graph/skills/tech-graph/references/style-3-blueprint.md +0 -113
  86. package/plugins/tech-graph/skills/tech-graph/references/style-4-notion-clean.md +0 -95
  87. package/plugins/tech-graph/skills/tech-graph/references/style-5-glassmorphism.md +0 -125
  88. package/plugins/tech-graph/skills/tech-graph/references/style-6-claude-official.md +0 -209
  89. package/plugins/tech-graph/skills/tech-graph/references/style-7-openai.md +0 -215
  90. package/plugins/tech-graph/skills/tech-graph/references/style-diagram-matrix.md +0 -135
  91. package/plugins/tech-graph/skills/tech-graph/references/svg-layout-best-practices.md +0 -100
  92. package/plugins/tech-graph/skills/tech-graph/references/svg-to-png.md +0 -115
  93. package/plugins/tech-graph/skills/tech-graph/scripts/README.md +0 -269
  94. package/plugins/tech-graph/skills/tech-graph/scripts/generate-diagram.sh +0 -181
  95. package/plugins/tech-graph/skills/tech-graph/scripts/generate-from-template.py +0 -1587
  96. package/plugins/tech-graph/skills/tech-graph/scripts/test-all-styles.sh +0 -143
  97. package/plugins/tech-graph/skills/tech-graph/scripts/validate-svg.sh +0 -306
  98. package/plugins/tech-graph/skills/tech-graph/templates/agent-architecture.svg +0 -28
  99. package/plugins/tech-graph/skills/tech-graph/templates/architecture.svg +0 -23
  100. package/plugins/tech-graph/skills/tech-graph/templates/comparison-matrix.svg +0 -14
  101. package/plugins/tech-graph/skills/tech-graph/templates/data-flow.svg +0 -28
  102. package/plugins/tech-graph/skills/tech-graph/templates/er-diagram.svg +0 -21
  103. package/plugins/tech-graph/skills/tech-graph/templates/flowchart.svg +0 -21
  104. package/plugins/tech-graph/skills/tech-graph/templates/sequence.svg +0 -20
  105. package/plugins/tech-graph/skills/tech-graph/templates/state-machine.svg +0 -20
  106. package/plugins/tech-graph/skills/tech-graph/templates/timeline.svg +0 -19
  107. package/plugins/tech-graph/skills/tech-graph/templates/use-case.svg +0 -21
@@ -1,581 +0,0 @@
1
- <!--
2
- template: 03-code-review-pr
3
- upstream: 03-code-review-pr.html
4
- slots:
5
- title: string # replaces first <h1> innerHTML
6
- -->
7
- <div class="page">
8
-
9
- <header class="pr-head">
10
- <div class="repo-line">acme/web · Pull Request #247</div>
11
- <h1>{{title}}</h1>
12
- <div class="meta-row">
13
- <div class="author">
14
- <div class="avatar">MO</div>
15
- <div>
16
- <div class="author-name">Mira Okafor</div>
17
- <div class="author-sub">opened 2 days ago</div>
18
- </div>
19
- </div>
20
- <div class="branch">
21
- mo/optimistic-tasks <span class="arrow">→</span> main
22
- </div>
23
- <div class="stat">
24
- <span class="add">+142</span> / <span class="del">−38</span>
25
- <span class="files">6 files changed</span>
26
- </div>
27
- </div>
28
- </header>
29
-
30
- <section class="prose">
31
- <h2>What this PR does</h2>
32
- <ul>
33
- <li>Replaces the await-then-refetch pattern in <code style="font-family:var(--mono);font-size:12.5px;background:var(--gray-150);padding:1px 5px;border-radius:4px">TaskList</code> with optimistic cache writes, so toggling or reordering a task feels instant instead of waiting ~300ms for the round-trip.</li>
34
- <li>Introduces a small <code style="font-family:var(--mono);font-size:12.5px;background:var(--gray-150);padding:1px 5px;border-radius:4px">useOptimisticTasks</code> hook that wraps the mutation, snapshots the previous list, and rolls back on error.</li>
35
- <li>Extends the API client to accept an idempotency key per mutation and adds a toast when a rollback fires.</li>
36
- </ul>
37
- </section>
38
-
39
- <section>
40
- <h2>Risk map</h2>
41
- <div class="risk-map">
42
- <a class="chip attention" href="#file-hook"><span class="dot"></span>useOptimisticTasks.ts</a>
43
- <a class="chip medium" href="#file-tasklist"><span class="dot"></span>TaskList.tsx</a>
44
- <a class="chip medium" href="#file-api"><span class="dot"></span>api/tasks.ts</a>
45
- <a class="chip safe" href="#file-toast"><span class="dot"></span>Toast.tsx</a>
46
- <a class="chip safe" href="#file-types"><span class="dot"></span>types/task.ts</a>
47
- <a class="chip safe" href="#file-test"><span class="dot"></span>TaskList.test.tsx</a>
48
- </div>
49
- <div class="legend">
50
- <span><span class="dot" style="background:var(--olive)"></span> safe</span>
51
- <span><span class="dot" style="background:#B89B6E"></span> worth a look</span>
52
- <span><span class="dot" style="background:var(--clay)"></span> needs attention</span>
53
- </div>
54
- </section>
55
-
56
- <section>
57
- <h2>Files</h2>
58
-
59
- <!-- File 1: hook (attention) -->
60
- <article class="file-card" id="file-hook">
61
- <div class="file-head">
62
- <div>
63
- <div class="file-path">src/hooks/useOptimisticTasks.ts</div>
64
- </div>
65
- <div style="display:flex;align-items:center;gap:12px">
66
- <span class="risk-tag attention">needs attention</span>
67
- <span class="file-delta"><span class="add">+58</span> <span class="del">−0</span></span>
68
- </div>
69
- </div>
70
- <div class="diff">
71
- <div class="diff-row hunk"><span class="ln"></span><span class="mark"></span><span class="code">@@ -0,0 +1,58 @@</span></div>
72
- <div class="diff-row add"><span class="ln">1</span><span class="mark">+</span><span class="code">import { useMutation, useQueryClient } from '@tanstack/react-query';</span></div>
73
- <div class="diff-row add"><span class="ln">2</span><span class="mark">+</span><span class="code">import { updateTask, TaskPatch } from '../api/tasks';</span></div>
74
- <div class="diff-row add"><span class="ln">3</span><span class="mark">+</span><span class="code">import type { Task } from '../types/task';</span></div>
75
- <div class="diff-row add"><span class="ln">4</span><span class="mark">+</span><span class="code"> </span></div>
76
- <div class="diff-row add"><span class="ln">5</span><span class="mark">+</span><span class="code">export function useOptimisticTasks(boardId: string) {</span></div>
77
- <div class="diff-row add"><span class="ln">6</span><span class="mark">+</span><span class="code"> const qc = useQueryClient();</span></div>
78
- <div class="diff-row add"><span class="ln">7</span><span class="mark">+</span><span class="code"> const key = ['tasks', boardId];</span></div>
79
- <div class="diff-row add"><span class="ln">8</span><span class="mark">+</span><span class="code"> </span></div>
80
- <div class="diff-row add"><span class="ln">9</span><span class="mark">+</span><span class="code"> return useMutation({</span></div>
81
- <div class="diff-row add"><span class="ln">10</span><span class="mark">+</span><span class="code"> mutationFn: (patch: TaskPatch) =&gt; updateTask(patch),</span></div>
82
- <div class="diff-row add"><span class="ln">11</span><span class="mark">+</span><span class="code"> onMutate: async (patch) =&gt; {</span></div>
83
- <div class="diff-row add"><span class="ln">12</span><span class="mark">+</span><span class="code"> const prev = qc.getQueryData&lt;Task[]&gt;(key);</span></div>
84
- <div class="diff-row add"><span class="ln">13</span><span class="mark">+</span><span class="code"> qc.setQueryData&lt;Task[]&gt;(key, (old = []) =&gt;</span></div>
85
- <div class="diff-row add"><span class="ln">14</span><span class="mark">+</span><span class="code"> old.map(t =&gt; t.id === patch.id ? { ...t, ...patch } : t)</span></div>
86
- <div class="diff-row add"><span class="ln">15</span><span class="mark">+</span><span class="code"> );</span></div>
87
- <div class="diff-row add"><span class="ln">16</span><span class="mark">+</span><span class="code"> return { prev };</span></div>
88
- <div class="diff-row add"><span class="ln">17</span><span class="mark">+</span><span class="code"> },</span></div>
89
- <div class="diff-row add"><span class="ln">18</span><span class="mark">+</span><span class="code"> onError: (_e, _p, ctx) =&gt; qc.setQueryData(key, ctx?.prev),</span></div>
90
- <div class="diff-row add"><span class="ln">19</span><span class="mark">+</span><span class="code"> });</span></div>
91
- <div class="diff-row add"><span class="ln">20</span><span class="mark">+</span><span class="code">}</span></div>
92
- </div>
93
- <div class="comments">
94
- <div class="bubble blocking">
95
- <div class="anchor">line 11</div>
96
- <p><span class="label">Blocking</span><code>onMutate</code> doesn't call <code>qc.cancelQueries(key)</code> first. If a background refetch lands between the optimistic write and the server response, it will clobber the optimistic state and the UI will flicker back to the old value.</p>
97
- </div>
98
- <div class="bubble nit">
99
- <div class="anchor">line 18</div>
100
- <p><span class="label">Nit</span>Rollback restores the list but never surfaces the error. Consider wiring the existing <code>pushToast</code> here so users know the toggle didn't stick.</p>
101
- </div>
102
- </div>
103
- </article>
104
-
105
- <!-- File 2: TaskList (medium) -->
106
- <article class="file-card" id="file-tasklist">
107
- <div class="file-head">
108
- <div>
109
- <div class="file-path">src/components/TaskList.tsx</div>
110
- </div>
111
- <div style="display:flex;align-items:center;gap:12px">
112
- <span class="risk-tag medium">worth a look</span>
113
- <span class="file-delta"><span class="add">+31</span> <span class="del">−24</span></span>
114
- </div>
115
- </div>
116
- <div class="diff">
117
- <div class="diff-row hunk"><span class="ln"></span><span class="mark"></span><span class="code">@@ -42,14 +42,17 @@ export function TaskList({ boardId }: Props) {</span></div>
118
- <div class="diff-row ctx"><span class="ln">42</span><span class="mark"> </span><span class="code"> const { data: tasks } = useTasks(boardId);</span></div>
119
- <div class="diff-row del"><span class="ln">43</span><span class="mark">-</span><span class="code"> const [pending, setPending] = useState&lt;string | null&gt;(null);</span></div>
120
- <div class="diff-row del"><span class="ln">44</span><span class="mark">-</span><span class="code"> </span></div>
121
- <div class="diff-row del"><span class="ln">45</span><span class="mark">-</span><span class="code"> async function toggle(task: Task) {</span></div>
122
- <div class="diff-row del"><span class="ln">46</span><span class="mark">-</span><span class="code"> setPending(task.id);</span></div>
123
- <div class="diff-row del"><span class="ln">47</span><span class="mark">-</span><span class="code"> await updateTask({ id: task.id, done: !task.done });</span></div>
124
- <div class="diff-row del"><span class="ln">48</span><span class="mark">-</span><span class="code"> await refetch();</span></div>
125
- <div class="diff-row del"><span class="ln">49</span><span class="mark">-</span><span class="code"> setPending(null);</span></div>
126
- <div class="diff-row del"><span class="ln">50</span><span class="mark">-</span><span class="code"> }</span></div>
127
- <div class="diff-row add"><span class="ln">43</span><span class="mark">+</span><span class="code"> const { mutate, isPending } = useOptimisticTasks(boardId);</span></div>
128
- <div class="diff-row add"><span class="ln">44</span><span class="mark">+</span><span class="code"> </span></div>
129
- <div class="diff-row add"><span class="ln">45</span><span class="mark">+</span><span class="code"> const toggle = (task: Task) =&gt;</span></div>
130
- <div class="diff-row add"><span class="ln">46</span><span class="mark">+</span><span class="code"> mutate({ id: task.id, done: !task.done });</span></div>
131
- <div class="diff-row ctx"><span class="ln">47</span><span class="mark"> </span><span class="code"> </span></div>
132
- <div class="diff-row ctx"><span class="ln">48</span><span class="mark"> </span><span class="code"> return (</span></div>
133
- <div class="diff-row ctx"><span class="ln">49</span><span class="mark"> </span><span class="code"> &lt;ul className="tasks"&gt;</span></div>
134
- <div class="diff-row del"><span class="ln">50</span><span class="mark">-</span><span class="code"> {tasks?.map(t =&gt; &lt;TaskRow key={t.id} task={t} busy={pending === t.id} /&gt;)}</span></div>
135
- <div class="diff-row add"><span class="ln">50</span><span class="mark">+</span><span class="code"> {tasks?.map(t =&gt; &lt;TaskRow key={t.id} task={t} onToggle={toggle} /&gt;)}</span></div>
136
- <div class="diff-row ctx"><span class="ln">51</span><span class="mark"> </span><span class="code"> &lt;/ul&gt;</span></div>
137
- </div>
138
- <div class="comments">
139
- <div class="bubble nit">
140
- <div class="anchor">line 43</div>
141
- <p><span class="label">Nit</span><code>isPending</code> is destructured but never read. Either drop it or pass it to <code>TaskRow</code> so the checkbox can dim while the request is in flight.</p>
142
- </div>
143
- </div>
144
- </article>
145
-
146
- <!-- File 3: api/tasks (medium) -->
147
- <article class="file-card" id="file-api">
148
- <div class="file-head">
149
- <div>
150
- <div class="file-path">src/api/tasks.ts</div>
151
- </div>
152
- <div style="display:flex;align-items:center;gap:12px">
153
- <span class="risk-tag medium">worth a look</span>
154
- <span class="file-delta"><span class="add">+19</span> <span class="del">−6</span></span>
155
- </div>
156
- </div>
157
- <div class="diff">
158
- <div class="diff-row hunk"><span class="ln"></span><span class="mark"></span><span class="code">@@ -12,10 +12,15 @@ export type TaskPatch = Partial&lt;Task&gt; &amp; { id: string };</span></div>
159
- <div class="diff-row ctx"><span class="ln">12</span><span class="mark"> </span><span class="code"> </span></div>
160
- <div class="diff-row del"><span class="ln">13</span><span class="mark">-</span><span class="code">export async function updateTask(patch: TaskPatch) {</span></div>
161
- <div class="diff-row del"><span class="ln">14</span><span class="mark">-</span><span class="code"> return http.patch(`/tasks/${patch.id}`, patch);</span></div>
162
- <div class="diff-row add"><span class="ln">13</span><span class="mark">+</span><span class="code">export async function updateTask(</span></div>
163
- <div class="diff-row add"><span class="ln">14</span><span class="mark">+</span><span class="code"> patch: TaskPatch,</span></div>
164
- <div class="diff-row add"><span class="ln">15</span><span class="mark">+</span><span class="code"> key = crypto.randomUUID(),</span></div>
165
- <div class="diff-row add"><span class="ln">16</span><span class="mark">+</span><span class="code">) {</span></div>
166
- <div class="diff-row add"><span class="ln">17</span><span class="mark">+</span><span class="code"> return http.patch(`/tasks/${patch.id}`, patch, {</span></div>
167
- <div class="diff-row add"><span class="ln">18</span><span class="mark">+</span><span class="code"> headers: { 'Idempotency-Key': key },</span></div>
168
- <div class="diff-row add"><span class="ln">19</span><span class="mark">+</span><span class="code"> });</span></div>
169
- <div class="diff-row ctx"><span class="ln">20</span><span class="mark"> </span><span class="code">}</span></div>
170
- </div>
171
- <div class="comments">
172
- <div class="bubble blocking">
173
- <div class="anchor">line 15</div>
174
- <p><span class="label">Blocking</span>Generating the idempotency key as a default parameter means retries from the mutation layer get a <em>new</em> key each time, which defeats the purpose. The key should be minted once in <code>onMutate</code> and threaded through.</p>
175
- </div>
176
- </div>
177
- </article>
178
-
179
- <!-- Collapsed files -->
180
- <details class="file-collapsed" id="file-toast">
181
- <summary>
182
- <span class="file-path">src/components/Toast.tsx</span>
183
- <span style="display:flex;align-items:center;gap:12px">
184
- <span class="risk-tag safe">safe</span>
185
- <span class="file-delta"><span class="add">+14</span> <span class="del">−2</span></span>
186
- </span>
187
- </summary>
188
- <div class="body">Adds a <code style="font-family:var(--mono)">variant="warning"</code> style and exports <code style="font-family:var(--mono)">pushToast</code>. Purely additive, no behaviour change for existing call sites.</div>
189
- </details>
190
-
191
- <details class="file-collapsed" id="file-types">
192
- <summary>
193
- <span class="file-path">src/types/task.ts</span>
194
- <span style="display:flex;align-items:center;gap:12px">
195
- <span class="risk-tag safe">safe</span>
196
- <span class="file-delta"><span class="add">+6</span> <span class="del">−2</span></span>
197
- </span>
198
- </summary>
199
- <div class="body">Widens <code style="font-family:var(--mono)">Task.status</code> to include <code style="font-family:var(--mono)">"archived"</code> and adds an optional <code style="font-family:var(--mono)">updatedAt</code> timestamp. Type-only change.</div>
200
- </details>
201
-
202
- <details class="file-collapsed" id="file-test">
203
- <summary>
204
- <span class="file-path">src/components/__tests__/TaskList.test.tsx</span>
205
- <span style="display:flex;align-items:center;gap:12px">
206
- <span class="risk-tag safe">safe</span>
207
- <span class="file-delta"><span class="add">+14</span> <span class="del">−4</span></span>
208
- </span>
209
- </summary>
210
- <div class="body">Adds a test asserting the row updates synchronously after click, and one asserting rollback when the mocked request rejects. Both pass locally.</div>
211
- </details>
212
- </section>
213
-
214
- <footer class="next-steps">
215
- <h2>Suggested next steps</h2>
216
- <ul class="checklist">
217
- <li>
218
- <input type="checkbox" id="step1">
219
- <label for="step1">Add <code>await qc.cancelQueries(key)</code> at the top of <code>onMutate</code> in <code>useOptimisticTasks.ts</code>.</label>
220
- </li>
221
- <li>
222
- <input type="checkbox" id="step2">
223
- <label for="step2">Move idempotency-key generation into the mutation context so retries reuse the same key.</label>
224
- </li>
225
- <li>
226
- <input type="checkbox" id="step3">
227
- <label for="step3">Either consume <code>isPending</code> in <code>TaskRow</code> or remove it from the destructure to keep lint clean.</label>
228
- </li>
229
- </ul>
230
- </footer>
231
-
232
- </div>
233
-
234
- <style>
235
- * { box-sizing: border-box; margin: 0; padding: 0; }
236
- .page {
237
- max-width: 920px;
238
- margin: 0 auto;
239
- }
240
- /* ---------- Header ---------- */
241
- header.pr-head {
242
- border: 1.5px solid var(--gray-300);
243
- border-radius: 12px;
244
- padding: 28px 32px;
245
- background: #fff;
246
- margin-bottom: 36px;
247
- }
248
- .repo-line {
249
- font-family: var(--mono);
250
- font-size: 12.5px;
251
- color: var(--gray-500);
252
- letter-spacing: 0.01em;
253
- margin-bottom: 10px;
254
- }
255
- h1 {
256
- font-family: var(--serif);
257
- font-weight: 500;
258
- font-size: 30px;
259
- line-height: 1.25;
260
- color: var(--slate);
261
- margin-bottom: 18px;
262
- }
263
- .meta-row {
264
- display: flex;
265
- align-items: center;
266
- flex-wrap: wrap;
267
- gap: 20px;
268
- }
269
- .author {
270
- display: flex;
271
- align-items: center;
272
- gap: 10px;
273
- }
274
- .avatar {
275
- width: 36px;
276
- height: 36px;
277
- border-radius: 50%;
278
- background: var(--oat);
279
- color: var(--slate);
280
- display: flex;
281
- align-items: center;
282
- justify-content: center;
283
- font-weight: 600;
284
- font-size: 13px;
285
- letter-spacing: 0.02em;
286
- border: 1.5px solid var(--gray-300);
287
- }
288
- .author-name { font-weight: 500; color: var(--slate); }
289
- .author-sub { font-size: 12px; color: var(--gray-500); }
290
- .branch {
291
- font-family: var(--mono);
292
- font-size: 12.5px;
293
- color: var(--gray-700);
294
- background: var(--gray-150);
295
- border: 1.5px solid var(--gray-300);
296
- border-radius: 8px;
297
- padding: 6px 10px;
298
- }
299
- .branch .arrow { color: var(--gray-500); margin: 0 6px; }
300
- .stat {
301
- font-family: var(--mono);
302
- font-size: 13px;
303
- }
304
- .stat .add { color: var(--olive); font-weight: 600; }
305
- .stat .del { color: var(--rust); font-weight: 600; }
306
- .stat .files { color: var(--gray-500); margin-left: 10px; }
307
- /* ---------- Section blocks ---------- */
308
- section { margin-bottom: 40px; }
309
- h2 {
310
- font-family: var(--serif);
311
- font-weight: 500;
312
- font-size: 21px;
313
- color: var(--slate);
314
- margin-bottom: 14px;
315
- }
316
- .prose ul {
317
- list-style: none;
318
- padding: 0;
319
- }
320
- .prose li {
321
- position: relative;
322
- padding-left: 22px;
323
- margin-bottom: 10px;
324
- }
325
- .prose li::before {
326
- content: "";
327
- position: absolute;
328
- left: 4px;
329
- top: 9px;
330
- width: 6px;
331
- height: 6px;
332
- background: var(--gray-500);
333
- border-radius: 2px;
334
- }
335
- /* ---------- Risk map ---------- */
336
- .risk-map {
337
- display: flex;
338
- flex-wrap: wrap;
339
- gap: 10px;
340
- }
341
- .chip {
342
- display: inline-flex;
343
- align-items: center;
344
- gap: 8px;
345
- padding: 8px 12px;
346
- border-radius: 8px;
347
- border: 1.5px solid var(--gray-300);
348
- font-family: var(--mono);
349
- font-size: 12.5px;
350
- color: var(--slate);
351
- text-decoration: none;
352
- background: #fff;
353
- transition: transform 0.12s ease;
354
- }
355
- .chip:hover { transform: translateY(-1px); }
356
- .chip .dot {
357
- width: 9px;
358
- height: 9px;
359
- border-radius: 50%;
360
- flex-shrink: 0;
361
- }
362
- .chip.safe { background: rgba(120,140,93,0.10); border-color: rgba(120,140,93,0.45); }
363
- .chip.safe .dot { background: var(--olive); }
364
- .chip.medium { background: var(--oat); }
365
- .chip.medium .dot { background: #B89B6E; }
366
- .chip.attention { background: rgba(217,119,87,0.12); border-color: rgba(217,119,87,0.55); }
367
- .chip.attention .dot { background: var(--clay); }
368
- .legend {
369
- margin-top: 12px;
370
- font-size: 12px;
371
- color: var(--gray-500);
372
- display: flex;
373
- gap: 18px;
374
- }
375
- .legend span { display: inline-flex; align-items: center; gap: 6px; }
376
- .legend .dot { width: 8px; height: 8px; border-radius: 50%; }
377
- /* ---------- File sections ---------- */
378
- .file-card {
379
- border: 1.5px solid var(--gray-300);
380
- border-radius: 12px;
381
- background: #fff;
382
- margin-bottom: 24px;
383
- overflow: hidden;
384
- scroll-margin-top: 20px;
385
- }
386
- .file-head {
387
- padding: 16px 20px;
388
- border-bottom: 1.5px solid var(--gray-150);
389
- display: flex;
390
- align-items: center;
391
- justify-content: space-between;
392
- gap: 12px;
393
- }
394
- .file-path {
395
- font-family: var(--mono);
396
- font-size: 13.5px;
397
- color: var(--slate);
398
- }
399
- .file-delta {
400
- font-family: var(--mono);
401
- font-size: 12px;
402
- color: var(--gray-500);
403
- }
404
- .file-delta .add { color: var(--olive); }
405
- .file-delta .del { color: var(--rust); }
406
- .risk-tag {
407
- font-size: 11px;
408
- text-transform: uppercase;
409
- letter-spacing: 0.06em;
410
- padding: 3px 8px;
411
- border-radius: 6px;
412
- font-weight: 600;
413
- }
414
- .risk-tag.safe { background: rgba(120,140,93,0.15); color: var(--olive); }
415
- .risk-tag.medium { background: var(--oat); color: #7A6A4F; }
416
- .risk-tag.attention { background: rgba(217,119,87,0.15); color: var(--clay); }
417
- /* ---------- Diff block ---------- */
418
- .diff {
419
- background: var(--slate);
420
- font-family: var(--mono);
421
- font-size: 12.5px;
422
- line-height: 1.7;
423
- overflow-x: auto;
424
- }
425
- .diff-row {
426
- display: grid;
427
- grid-template-columns: 48px 18px 1fr;
428
- align-items: baseline;
429
- padding: 0 14px 0 0;
430
- white-space: pre;
431
- }
432
- .diff-row .ln {
433
- text-align: right;
434
- padding-right: 14px;
435
- color: var(--gray-500);
436
- user-select: none;
437
- }
438
- .diff-row .mark {
439
- text-align: center;
440
- color: var(--gray-500);
441
- }
442
- .diff-row .code { color: #E8E6DC; }
443
- .diff-row.ctx .code { color: #B8B6AC; }
444
- .diff-row.add { background: rgba(120,140,93,0.15); }
445
- .diff-row.add .mark { color: var(--olive); }
446
- .diff-row.del { background: rgba(176,74,63,0.15); }
447
- .diff-row.del .mark { color: var(--rust); }
448
- .diff-row.hunk {
449
- background: rgba(255,255,255,0.04);
450
- color: var(--gray-500);
451
- }
452
- .diff-row.hunk .code { color: var(--gray-500); }
453
- /* ---------- Review comments ---------- */
454
- .comments {
455
- padding: 18px 20px 20px;
456
- display: flex;
457
- flex-direction: column;
458
- gap: 14px;
459
- background: var(--gray-150);
460
- }
461
- .bubble {
462
- position: relative;
463
- background: #fff;
464
- border: 1.5px solid var(--gray-300);
465
- border-left-width: 4px;
466
- border-radius: 8px;
467
- padding: 12px 14px 12px 16px;
468
- max-width: 680px;
469
- }
470
- .bubble.blocking { border-left-color: var(--clay); }
471
- .bubble.nit { border-left-color: var(--gray-300); }
472
- .bubble::before {
473
- content: "";
474
- position: absolute;
475
- left: -9px;
476
- top: 16px;
477
- width: 12px;
478
- height: 12px;
479
- background: #fff;
480
- border-left: 1.5px solid var(--gray-300);
481
- border-bottom: 1.5px solid var(--gray-300);
482
- transform: rotate(45deg);
483
- }
484
- .bubble.blocking::before { border-left-color: var(--clay); border-bottom-color: var(--clay); }
485
- .bubble .anchor {
486
- font-family: var(--mono);
487
- font-size: 11.5px;
488
- color: var(--gray-500);
489
- margin-bottom: 4px;
490
- }
491
- .bubble .label {
492
- display: inline-block;
493
- font-size: 10.5px;
494
- text-transform: uppercase;
495
- letter-spacing: 0.08em;
496
- font-weight: 700;
497
- margin-right: 8px;
498
- }
499
- .bubble.blocking .label { color: var(--clay); }
500
- .bubble.nit .label { color: var(--gray-500); }
501
- .bubble p { font-size: 13.5px; color: var(--gray-700); }
502
- .bubble code {
503
- font-family: var(--mono);
504
- font-size: 12.5px;
505
- background: var(--gray-150);
506
- padding: 1px 5px;
507
- border-radius: 4px;
508
- }
509
- /* ---------- Collapsed files ---------- */
510
- details.file-collapsed {
511
- border: 1.5px solid var(--gray-300);
512
- border-radius: 12px;
513
- background: #fff;
514
- margin-bottom: 14px;
515
- scroll-margin-top: 20px;
516
- }
517
- details.file-collapsed summary {
518
- list-style: none;
519
- cursor: pointer;
520
- padding: 14px 20px;
521
- display: flex;
522
- align-items: center;
523
- justify-content: space-between;
524
- gap: 12px;
525
- }
526
- details.file-collapsed summary::-webkit-details-marker { display: none; }
527
- details.file-collapsed summary::after {
528
- content: "+";
529
- font-family: var(--mono);
530
- color: var(--gray-500);
531
- font-size: 16px;
532
- }
533
- details.file-collapsed[open] summary::after { content: "−"; }
534
- details.file-collapsed .body {
535
- padding: 0 20px 16px;
536
- font-size: 13.5px;
537
- color: var(--gray-700);
538
- }
539
- /* ---------- Footer ---------- */
540
- footer.next-steps {
541
- border: 1.5px solid var(--gray-300);
542
- border-radius: 12px;
543
- background: #fff;
544
- padding: 24px 28px;
545
- }
546
- .checklist { list-style: none; padding: 0; }
547
- .checklist li {
548
- display: flex;
549
- align-items: flex-start;
550
- gap: 12px;
551
- padding: 8px 0;
552
- }
553
- .checklist input[type="checkbox"] {
554
- width: 17px;
555
- height: 17px;
556
- margin-top: 2px;
557
- accent-color: var(--olive);
558
- cursor: pointer;
559
- }
560
- .checklist label { cursor: pointer; flex: 1; }
561
- .checklist code {
562
- font-family: var(--mono);
563
- font-size: 12.5px;
564
- background: var(--gray-150);
565
- padding: 1px 5px;
566
- border-radius: 4px;
567
- }
568
- </style>
569
-
570
- <script>
571
- // Briefly highlight a file card when reached via the risk-map anchors.
572
- document.querySelectorAll('.risk-map a').forEach(function (a) {
573
- a.addEventListener('click', function () {
574
- var target = document.querySelector(a.getAttribute('href'));
575
- if (!target) return;
576
- target.style.transition = 'box-shadow 180ms ease';
577
- target.style.boxShadow = '0 0 0 3px rgba(217,119,87,0.35)';
578
- setTimeout(function () { target.style.boxShadow = 'none'; }, 1400);
579
- });
580
- });
581
- </script>