@texuli/tools 0.0.0-stage → 0.1.0-next.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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -2
  3. package/dist/a2ui/from-a2ui.d.ts +35 -0
  4. package/dist/a2ui/from-a2ui.js +180 -0
  5. package/dist/a2ui/index.d.ts +11 -0
  6. package/dist/a2ui/index.js +11 -0
  7. package/dist/a2ui/props.d.ts +10 -0
  8. package/dist/a2ui/props.js +94 -0
  9. package/dist/a2ui/schema.d.ts +26 -0
  10. package/dist/a2ui/schema.js +193 -0
  11. package/dist/a2ui/to-a2ui.d.ts +30 -0
  12. package/dist/a2ui/to-a2ui.js +119 -0
  13. package/dist/a2ui/types.d.ts +71 -0
  14. package/dist/a2ui/types.js +11 -0
  15. package/dist/cli-add/add.d.ts +21 -0
  16. package/dist/cli-add/add.js +241 -0
  17. package/dist/cli-add/cli.d.ts +25 -0
  18. package/dist/cli-add/cli.js +157 -0
  19. package/dist/cli-add/index.d.ts +12 -0
  20. package/dist/cli-add/index.js +11 -0
  21. package/dist/cli-add/paths.d.ts +4 -0
  22. package/dist/cli-add/paths.js +4 -0
  23. package/dist/cli-add/provenance.d.ts +32 -0
  24. package/dist/cli-add/provenance.js +78 -0
  25. package/dist/cli-add/registry.d.ts +19 -0
  26. package/dist/cli-add/registry.js +50 -0
  27. package/dist/cli-add/types.d.ts +71 -0
  28. package/dist/cli-add/types.js +4 -0
  29. package/dist/cli-init/cli.d.ts +25 -0
  30. package/dist/cli-init/cli.js +212 -0
  31. package/dist/cli-init/config.d.ts +10 -0
  32. package/dist/cli-init/config.js +62 -0
  33. package/dist/cli-init/detect.d.ts +13 -0
  34. package/dist/cli-init/detect.js +42 -0
  35. package/dist/cli-init/files.d.ts +18 -0
  36. package/dist/cli-init/files.js +59 -0
  37. package/dist/cli-init/index.d.ts +14 -0
  38. package/dist/cli-init/index.js +13 -0
  39. package/dist/cli-init/init.d.ts +14 -0
  40. package/dist/cli-init/init.js +157 -0
  41. package/dist/cli-init/safe-path.d.ts +2 -0
  42. package/dist/cli-init/safe-path.js +26 -0
  43. package/dist/cli-init/theme-apply.d.ts +2 -0
  44. package/dist/cli-init/theme-apply.js +69 -0
  45. package/dist/cli-init/themes.d.ts +37 -0
  46. package/dist/cli-init/themes.js +83 -0
  47. package/dist/cli-init/types.d.ts +50 -0
  48. package/dist/cli-init/types.js +1 -0
  49. package/dist/cli-init/wire.d.ts +20 -0
  50. package/dist/cli-init/wire.js +90 -0
  51. package/dist/cli-update/cli.d.ts +26 -0
  52. package/dist/cli-update/cli.js +161 -0
  53. package/dist/cli-update/index.d.ts +11 -0
  54. package/dist/cli-update/index.js +10 -0
  55. package/dist/cli-update/lines.d.ts +38 -0
  56. package/dist/cli-update/lines.js +189 -0
  57. package/dist/cli-update/provenance.d.ts +14 -0
  58. package/dist/cli-update/provenance.js +51 -0
  59. package/dist/cli-update/types.d.ts +83 -0
  60. package/dist/cli-update/types.js +1 -0
  61. package/dist/cli-update/update.d.ts +12 -0
  62. package/dist/cli-update/update.js +261 -0
  63. package/dist/elements/content.d.ts +15 -0
  64. package/dist/elements/content.js +53 -0
  65. package/dist/elements/define.d.ts +49 -0
  66. package/dist/elements/define.js +281 -0
  67. package/dist/elements/index.d.ts +6 -0
  68. package/dist/elements/index.js +6 -0
  69. package/dist/golden/axe.d.ts +32 -0
  70. package/dist/golden/axe.js +22 -0
  71. package/dist/golden/catalog.d.ts +24 -0
  72. package/dist/golden/catalog.js +85 -0
  73. package/dist/golden/cli.d.ts +9 -0
  74. package/dist/golden/cli.js +45 -0
  75. package/dist/golden/guidance.d.ts +12 -0
  76. package/dist/golden/guidance.js +171 -0
  77. package/dist/golden/index.d.ts +17 -0
  78. package/dist/golden/index.js +17 -0
  79. package/dist/golden/outline.d.ts +21 -0
  80. package/dist/golden/outline.js +68 -0
  81. package/dist/golden/paint.d.ts +21 -0
  82. package/dist/golden/paint.js +103 -0
  83. package/dist/golden/report.d.ts +28 -0
  84. package/dist/golden/report.js +64 -0
  85. package/dist/golden/score.d.ts +16 -0
  86. package/dist/golden/score.js +116 -0
  87. package/dist/golden/sinks.d.ts +8 -0
  88. package/dist/golden/sinks.js +11 -0
  89. package/dist/golden/tasks.d.ts +4 -0
  90. package/dist/golden/tasks.js +686 -0
  91. package/dist/golden/types.d.ts +54 -0
  92. package/dist/golden/types.js +9 -0
  93. package/dist/index.d.ts +8 -0
  94. package/dist/index.js +8 -0
  95. package/dist/internal/paths.d.ts +56 -0
  96. package/dist/internal/paths.js +186 -0
  97. package/dist/llms/bundle.d.ts +6 -0
  98. package/dist/llms/bundle.js +47 -0
  99. package/dist/llms/cli.d.ts +24 -0
  100. package/dist/llms/cli.js +104 -0
  101. package/dist/llms/format.d.ts +35 -0
  102. package/dist/llms/format.js +166 -0
  103. package/dist/llms/index.d.ts +9 -0
  104. package/dist/llms/index.js +8 -0
  105. package/dist/llms/types.d.ts +51 -0
  106. package/dist/llms/types.js +1 -0
  107. package/dist/llms/write.d.ts +14 -0
  108. package/dist/llms/write.js +49 -0
  109. package/dist/mcp/index.d.ts +2 -0
  110. package/dist/mcp/index.js +2 -0
  111. package/dist/mcp/server.d.ts +20 -0
  112. package/dist/mcp/server.js +326 -0
  113. package/dist/mcp/stdio.d.ts +3 -0
  114. package/dist/mcp/stdio.js +34 -0
  115. package/package.json +63 -4
@@ -0,0 +1,686 @@
1
+ /**
2
+ * The agent golden set: 30 pre-registered interface tasks. Each has a brief a
3
+ * model receives, the components the interface needs, the guidance it baits
4
+ * (`traps`), and a reference tree that passes every scorer check. Changing a
5
+ * task changes what a model is measured against, so tasks are append-only:
6
+ * add `g31-…` rather than editing a brief.
7
+ *
8
+ * All content is fictional (Harbor, Pebble and friends; `example.com` hosts).
9
+ */
10
+ const NAVIGATION = 'Application navigation, account controls or mutations.';
11
+ const CHROME = 'App chrome shells (sidebar, top-nav, dialogs)';
12
+ const node = (id, props = {}, children = []) => children.length ? { id, props, children } : { id, props };
13
+ const page = (title, description, children) => node('layout-page', { title, description }, children);
14
+ const doc = (title, children) => node('layout-doc', { title }, children);
15
+ const deck = (title, children) => node('layout-deck', { title }, children);
16
+ const card = (title, children) => node('layout-card', { title }, children);
17
+ const grid = (columns, children) => node('layout-grid', { columns }, children);
18
+ const block = (value) => node('blocks-text', { block: value });
19
+ const heading = (level, text) => block({ type: 'heading', level, text });
20
+ const text = (markdown) => block({ type: 'text', markdown });
21
+ const list = (items, ordered = false) => block({ type: 'list', ordered, items: items.map((item) => ({ text: item })) });
22
+ const quote = (value, cite) => block(cite ? { type: 'quote', quote: value, cite } : { type: 'quote', quote: value });
23
+ const callout = (tone, title, body) => block({ type: 'callout', tone, title, body });
24
+ const data = (value) => node('blocks-data', { block: value });
25
+ const kpis = (items) => data({
26
+ type: 'kpi',
27
+ items: items.map(([label, value, delta]) => delta ? { label, value, delta } : { label, value }),
28
+ });
29
+ const stats = (items) => data({ type: 'stat', items: items.map(([label, value]) => ({ label, value })) });
30
+ const table = (caption, columns, rows) => data({ type: 'table', caption, columns: columns.map(([id, label]) => ({ id, label })), rows });
31
+ const points = (labels, values) => labels.map((x, index) => ({ x, y: values[index] ?? null }));
32
+ const series = (id, label, labels, values) => ({
33
+ id,
34
+ label,
35
+ points: points(labels, values),
36
+ });
37
+ const WEEKS = ['W1', 'W2', 'W3', 'W4', 'W5', 'W6'];
38
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
39
+ const cartesian = (id, title, description, s) => node(id, { title, description, series: s });
40
+ const parts = (pairs) => pairs.map(([label, value]) => ({
41
+ id: label.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
42
+ label,
43
+ value,
44
+ }));
45
+ const PART_LABELS = { table: 'Data table', category: 'Category', value: 'Value' };
46
+ const partWhole = (id, title, description, pairs) => node(id, { title, description, data: parts(pairs), labels: PART_LABELS });
47
+ const image = (src, alt) => node('media-image', { src, alt, width: 640, height: 360 });
48
+ export const GOLDEN_TASKS = Object.freeze([
49
+ {
50
+ id: 'g01-weekly-support-digest',
51
+ title: 'Weekly support digest',
52
+ brief: 'Build a weekly support digest for the Harbor help desk: three headline KPIs (open tickets, median first reply, satisfaction), a line chart of tickets opened per week for six weeks, and a table of the five busiest queues.',
53
+ tier: 'untrusted',
54
+ mustInclude: ['layout-page', 'blocks-data', 'charts-line'],
55
+ traps: [],
56
+ reference: page('Weekly support digest', 'Harbor help desk, week 24', [
57
+ kpis([
58
+ ['Open tickets', '142', '-8%'],
59
+ ['Median first reply', '38 min', '-4 min'],
60
+ ['Satisfaction', '94%', '+1 pt'],
61
+ ]),
62
+ card('Tickets per week', [
63
+ cartesian('charts-line', 'Tickets opened', 'Tickets opened per week over six weeks', [
64
+ series('opened', 'Opened', WEEKS, [310, 284, 296, 270, 255, 248]),
65
+ ]),
66
+ ]),
67
+ card('Busiest queues', [
68
+ table('Five busiest queues this week', [
69
+ ['queue', 'Queue'],
70
+ ['open', 'Open'],
71
+ ], [
72
+ { queue: 'Billing', open: 41 },
73
+ { queue: 'Shipping', open: 33 },
74
+ { queue: 'Accounts', open: 27 },
75
+ { queue: 'Returns', open: 22 },
76
+ { queue: 'Hardware', open: 19 },
77
+ ]),
78
+ ]),
79
+ ]),
80
+ },
81
+ {
82
+ id: 'g02-release-notes',
83
+ title: 'Release notes',
84
+ brief: 'Write release notes for Pebble 4.2 as a document: a short summary, a "New" section and a "Fixed" section as bullet lists, and a note warning that the old export format is removed next release.',
85
+ tier: 'untrusted',
86
+ mustInclude: ['layout-doc', 'blocks-text'],
87
+ traps: [],
88
+ reference: doc('Pebble 4.2 release notes', [
89
+ text('Pebble 4.2 makes shared boards faster and adds keyboard shortcuts for the editor.'),
90
+ heading(2, 'New'),
91
+ list(['Keyboard shortcuts in the board editor', 'Board templates for planning weeks']),
92
+ heading(2, 'Fixed'),
93
+ list(['Comments no longer jump while typing', 'Dates show in the viewer time zone']),
94
+ callout('warning', 'Export format change', 'The 3.x export format is removed in 4.3. Re-export old boards before then.'),
95
+ ]),
96
+ },
97
+ {
98
+ id: 'g03-onboarding-handbook',
99
+ title: 'Team onboarding handbook',
100
+ brief: 'Create the first page of the Harbor team onboarding handbook: a welcome paragraph, the first-week checklist as an ordered list, and a quote from the team lead. The site header already has the navigation, so do not add a menu of links.',
101
+ tier: 'untrusted',
102
+ mustInclude: ['layout-doc', 'blocks-text'],
103
+ traps: [NAVIGATION],
104
+ reference: doc('Welcome to Harbor', [
105
+ text('This handbook covers how the team plans, ships and supports Harbor.'),
106
+ heading(2, 'Your first week'),
107
+ list([
108
+ 'Meet your onboarding buddy',
109
+ 'Set up the development sandbox',
110
+ 'Ship a small fix with a pair',
111
+ ], true),
112
+ quote('Ask early and ask often; nobody expects you to know the codebase yet.', 'Rina Okafor, team lead'),
113
+ ]),
114
+ },
115
+ {
116
+ id: 'g04-quarterly-revenue',
117
+ title: 'Quarterly revenue review',
118
+ brief: 'Build a quarterly revenue review for Pebble: revenue, net retention and new logos as stats, a stacked bar chart of revenue by plan for six months, and a donut of revenue share by region.',
119
+ tier: 'untrusted',
120
+ mustInclude: ['layout-page', 'charts-stacked-bar', 'charts-donut'],
121
+ traps: [],
122
+ reference: page('Quarterly revenue review', 'Pebble, second quarter', [
123
+ stats([
124
+ ['Revenue', '$1.42M'],
125
+ ['Net retention', '112%'],
126
+ ['New logos', '38'],
127
+ ]),
128
+ card('Revenue by plan', [
129
+ cartesian('charts-stacked-bar', 'Revenue by plan', 'Monthly revenue split by plan, in thousands', [
130
+ series('team', 'Team', MONTHS, [120, 126, 131, 138, 142, 150]),
131
+ series('business', 'Business', MONTHS, [90, 94, 99, 101, 108, 112]),
132
+ ]),
133
+ ]),
134
+ card('Revenue by region', [
135
+ partWhole('charts-donut', 'Revenue share', 'Share of quarterly revenue by region', [
136
+ ['North', 42],
137
+ ['South', 23],
138
+ ['West', 35],
139
+ ]),
140
+ ]),
141
+ ]),
142
+ },
143
+ {
144
+ id: 'g05-incident-postmortem',
145
+ title: 'Incident postmortem',
146
+ brief: 'Write the postmortem for the Harbor checkout outage: summary, an ordered timeline, a quote from the on-call engineer, and a callout with the follow-up owner.',
147
+ tier: 'untrusted',
148
+ mustInclude: ['layout-doc', 'blocks-text'],
149
+ traps: [],
150
+ reference: doc('Checkout outage postmortem', [
151
+ text('Checkout returned errors for 23 minutes after a configuration change. No data was lost.'),
152
+ heading(2, 'Timeline'),
153
+ list(['09:02 configuration deployed', '09:05 error alerts fire', '09:25 change rolled back'], true),
154
+ quote('The rollback was quick once we saw the config diff.', 'Theo Marsh, on call'),
155
+ callout('info', 'Follow-up', 'Ines Varga owns adding a config canary by the next release.'),
156
+ ]),
157
+ },
158
+ {
159
+ id: 'g06-plan-comparison',
160
+ title: 'Plan comparison',
161
+ brief: 'Show a comparison of the three Pebble plans (Starter, Team, Business) as a table with seats, storage and support level. Do not add buy or upgrade buttons; the billing page handles purchases.',
162
+ tier: 'untrusted',
163
+ mustInclude: ['layout-page', 'blocks-data'],
164
+ traps: [NAVIGATION],
165
+ reference: page('Compare plans', 'What each Pebble plan includes', [
166
+ table('Pebble plans', [
167
+ ['plan', 'Plan'],
168
+ ['seats', 'Seats'],
169
+ ['storage', 'Storage'],
170
+ ['support', 'Support'],
171
+ ], [
172
+ { plan: 'Starter', seats: 3, storage: '5 GB', support: 'Community' },
173
+ { plan: 'Team', seats: 25, storage: '100 GB', support: 'Email' },
174
+ { plan: 'Business', seats: 250, storage: '1 TB', support: 'Priority' },
175
+ ]),
176
+ ]),
177
+ },
178
+ {
179
+ id: 'g07-harbor-traffic-map',
180
+ title: 'Harbor district traffic',
181
+ brief: 'Map foot traffic across the Harbor districts with a point map, with a short intro paragraph above it.',
182
+ tier: 'untrusted',
183
+ mustInclude: ['layout-page', 'charts-geo-point-map'],
184
+ traps: [],
185
+ reference: page('District foot traffic', 'Harbor, Saturday counts', [
186
+ text('Counts come from the fictional Harbor sensor network, rounded to the nearest hundred.'),
187
+ card('Traffic by district', [
188
+ node('charts-geo-point-map', {
189
+ title: 'Foot traffic',
190
+ description: 'Saturday visitors by district',
191
+ points: [
192
+ { id: 'p1', label: 'Old Town square', regionId: 'old-town', value: 4200 },
193
+ { id: 'p2', label: 'Harbor Point pier', regionId: 'harbor-point', value: 3800 },
194
+ { id: 'p3', label: 'West Shore market', regionId: 'west-shore', value: 2100 },
195
+ ],
196
+ }),
197
+ ]),
198
+ ]),
199
+ },
200
+ {
201
+ id: 'g08-pricing-faq',
202
+ title: 'Pricing FAQ',
203
+ brief: 'Write the pricing FAQ for Pebble: four questions with short answers. Visitors already see "Sign in" and "Buy now" in the page header, so do not repeat them.',
204
+ tier: 'untrusted',
205
+ mustInclude: ['layout-doc', 'blocks-text'],
206
+ traps: [NAVIGATION],
207
+ reference: doc('Pricing questions', [
208
+ heading(2, 'Can I change plans later?'),
209
+ text('Yes. Changes apply from your next billing period.'),
210
+ heading(2, 'Is there a free trial?'),
211
+ text('Every plan starts with a 14-day trial.'),
212
+ heading(2, 'Do you offer discounts for nonprofits?'),
213
+ text('Registered nonprofits get 30% off the Team plan.'),
214
+ heading(2, 'How is a seat counted?'),
215
+ text('A seat is anyone who signed in during the billing period.'),
216
+ ]),
217
+ },
218
+ {
219
+ id: 'g09-hiring-funnel',
220
+ title: 'Hiring funnel',
221
+ brief: 'Show the Harbor engineering hiring funnel for the quarter, from applications to offers accepted.',
222
+ tier: 'untrusted',
223
+ mustInclude: ['layout-page', 'charts-funnel'],
224
+ traps: [],
225
+ reference: page('Hiring funnel', 'Engineering, this quarter', [
226
+ card('From application to offer', [
227
+ node('charts-funnel', {
228
+ title: 'Hiring funnel',
229
+ description: 'Candidates at each hiring stage',
230
+ steps: [
231
+ { id: 'applied', label: 'Applied', value: 480 },
232
+ { id: 'screened', label: 'Screened', value: 160 },
233
+ { id: 'onsite', label: 'Onsite', value: 42 },
234
+ { id: 'offer', label: 'Offer accepted', value: 9 },
235
+ ],
236
+ }),
237
+ ]),
238
+ ]),
239
+ },
240
+ {
241
+ id: 'g10-energy-usage',
242
+ title: 'Building energy usage',
243
+ brief: 'Build an energy overview for the Pebble office: a grid of three cards, each with a sparkline of the last eight days for electricity, heating and water.',
244
+ tier: 'untrusted',
245
+ mustInclude: ['layout-grid', 'charts-sparkline'],
246
+ traps: [],
247
+ reference: page('Energy usage', 'Pebble office, last eight days', [
248
+ grid(3, [
249
+ card('Electricity', [
250
+ node('charts-sparkline', {
251
+ label: 'Electricity in kWh',
252
+ values: [42, 40, 44, 39, 38, 41, 37, 36],
253
+ }),
254
+ ]),
255
+ card('Heating', [
256
+ node('charts-sparkline', {
257
+ label: 'Heating in kWh',
258
+ values: [80, 78, 75, 70, 72, 69, 66, 64],
259
+ }),
260
+ ]),
261
+ card('Water', [
262
+ node('charts-sparkline', {
263
+ label: 'Water in liters',
264
+ values: [510, 495, 520, 480, 470, 505, 490, 485],
265
+ }),
266
+ ]),
267
+ ]),
268
+ ]),
269
+ },
270
+ {
271
+ id: 'g11-team-photos',
272
+ title: 'Team offsite photos',
273
+ brief: 'Make a page of three photos from the Harbor team offsite, each with alternative text, and a short intro.',
274
+ tier: 'untrusted',
275
+ mustInclude: ['layout-page', 'media-image'],
276
+ traps: [],
277
+ reference: page('Team offsite', 'Harbor, spring offsite', [
278
+ text('Two days of planning by the fictional Lake Arden.'),
279
+ grid(3, [
280
+ image('images/offsite-workshop.webp', 'Six people around a whiteboard covered in sticky notes'),
281
+ image('images/offsite-lake.webp', 'The team walking along a lake path at sunset'),
282
+ image('images/offsite-dinner.webp', 'A long table set for a shared dinner'),
283
+ ]),
284
+ ]),
285
+ },
286
+ {
287
+ id: 'g12-course-syllabus',
288
+ title: 'Course syllabus',
289
+ brief: 'Write a syllabus for a six-week "Intro to data visualization" course: overview, weekly topics as an ordered list, and grading.',
290
+ tier: 'untrusted',
291
+ mustInclude: ['layout-doc', 'blocks-text'],
292
+ traps: [],
293
+ reference: doc('Intro to data visualization', [
294
+ text('Six weeks of practical charting with fictional datasets.'),
295
+ heading(2, 'Weekly topics'),
296
+ list([
297
+ 'Seeing data',
298
+ 'Choosing a chart',
299
+ 'Color and contrast',
300
+ 'Text and labels',
301
+ 'Interaction',
302
+ 'Critique',
303
+ ], true),
304
+ heading(2, 'Grading'),
305
+ list(['Weekly exercises: 60%', 'Final project: 40%']),
306
+ ]),
307
+ },
308
+ {
309
+ id: 'g13-customer-quotes',
310
+ title: 'Customer quotes',
311
+ brief: 'Show three customer quotes about Pebble boards in a grid, each attributed to a fictional customer.',
312
+ tier: 'untrusted',
313
+ mustInclude: ['layout-grid', 'blocks-text'],
314
+ traps: [],
315
+ reference: page('What teams say', 'Quotes from fictional Pebble customers', [
316
+ grid(3, [
317
+ quote('Our planning meeting got twenty minutes shorter.', 'Mara Lind, Northwind Studio'),
318
+ quote('The board templates saved our first week.', 'Jonah Pike, Fernhill Labs'),
319
+ quote('Everyone finally looks at the same plan.', 'Ada Brook, Orchard Co.'),
320
+ ]),
321
+ ]),
322
+ },
323
+ {
324
+ id: 'g14-budget-treemap',
325
+ title: 'Budget breakdown',
326
+ brief: 'Break down the Harbor annual budget by department and team with a treemap.',
327
+ tier: 'untrusted',
328
+ mustInclude: ['layout-page', 'charts-treemap'],
329
+ traps: [],
330
+ reference: page('Annual budget', 'Harbor, by department', [
331
+ card('Budget by team', [
332
+ node('charts-treemap', {
333
+ title: 'Budget breakdown',
334
+ description: 'Annual budget by department and team, in thousands',
335
+ labels: PART_LABELS,
336
+ root: {
337
+ id: 'budget',
338
+ label: 'Budget',
339
+ children: [
340
+ {
341
+ id: 'product',
342
+ label: 'Product',
343
+ children: [
344
+ { id: 'design', label: 'Design', value: 320 },
345
+ { id: 'engineering', label: 'Engineering', value: 910 },
346
+ ],
347
+ },
348
+ { id: 'support', label: 'Support', value: 280 },
349
+ { id: 'sales', label: 'Sales', value: 450 },
350
+ ],
351
+ },
352
+ }),
353
+ ]),
354
+ ]),
355
+ },
356
+ {
357
+ id: 'g15-service-dependencies',
358
+ title: 'Service dependencies',
359
+ brief: 'Show which Harbor services depend on each other as a network graph, with a sentence explaining how to read it.',
360
+ tier: 'untrusted',
361
+ mustInclude: ['layout-page', 'charts-network'],
362
+ traps: [],
363
+ reference: page('Service dependencies', 'Harbor platform', [
364
+ text('Each link points from a service to a service it calls.'),
365
+ card('Call graph', [
366
+ node('charts-network', {
367
+ title: 'Service dependencies',
368
+ description: 'Services and the services they call',
369
+ nodes: [
370
+ { id: 'web', label: 'Web' },
371
+ { id: 'api', label: 'API' },
372
+ { id: 'billing', label: 'Billing' },
373
+ { id: 'search', label: 'Search' },
374
+ ],
375
+ links: [
376
+ { source: 'web', target: 'api', value: 3 },
377
+ { source: 'api', target: 'billing', value: 1 },
378
+ { source: 'api', target: 'search', value: 2 },
379
+ ],
380
+ }),
381
+ ]),
382
+ ]),
383
+ },
384
+ {
385
+ id: 'g16-sprint-review-deck',
386
+ title: 'Sprint review deck',
387
+ brief: 'Make a three-slide sprint review deck: goals met, a bar chart of points completed per team, and next sprint focus.',
388
+ tier: 'untrusted',
389
+ mustInclude: ['layout-deck', 'charts-bar'],
390
+ traps: [],
391
+ reference: deck('Sprint 18 review', [
392
+ card('Goals met', [list(['Shared boards beta shipped', 'Search latency halved'])]),
393
+ card('Points completed', [
394
+ cartesian('charts-bar', 'Points completed', 'Story points completed per team this sprint', [
395
+ series('points', 'Points', ['Boards', 'Search', 'Mobile'], [34, 28, 21]),
396
+ ]),
397
+ ]),
398
+ card('Next sprint', [list(['Offline mode', 'Board permissions'])]),
399
+ ]),
400
+ },
401
+ {
402
+ id: 'g17-service-status',
403
+ title: 'Service status',
404
+ brief: 'Build a public status page for Pebble: overall status as a callout, uptime stats for three services, and recent incidents as a list. Account links like "Sign in" or "My account" belong to the site header, not this page.',
405
+ tier: 'untrusted',
406
+ mustInclude: ['layout-page', 'blocks-data'],
407
+ traps: [NAVIGATION],
408
+ reference: page('Pebble status', 'Live service health', [
409
+ callout('success', 'All systems operational', 'No incidents in the last 72 hours.'),
410
+ stats([
411
+ ['Web app uptime', '99.98%'],
412
+ ['API uptime', '99.95%'],
413
+ ['Sync uptime', '99.91%'],
414
+ ]),
415
+ card('Recent incidents', [
416
+ list([
417
+ 'Jun 4: delayed sync, resolved in 12 minutes',
418
+ 'May 28: API errors, resolved in 6 minutes',
419
+ ]),
420
+ ]),
421
+ ]),
422
+ },
423
+ {
424
+ id: 'g18-recipe',
425
+ title: 'Recipe',
426
+ brief: 'Write a recipe page for lemon barley soup: an intro, ingredients as a list and the steps as an ordered list.',
427
+ tier: 'untrusted',
428
+ mustInclude: ['layout-doc', 'blocks-text'],
429
+ traps: [],
430
+ reference: doc('Lemon barley soup', [
431
+ text('A bright, filling soup for four.'),
432
+ heading(2, 'Ingredients'),
433
+ list(['1 cup pearl barley', '1 onion', '2 carrots', '6 cups stock', '1 lemon']),
434
+ heading(2, 'Steps'),
435
+ list([
436
+ 'Soften the onion and carrots',
437
+ 'Add barley and stock and simmer 40 minutes',
438
+ 'Finish with lemon juice',
439
+ ], true),
440
+ ]),
441
+ },
442
+ {
443
+ id: 'g19-survey-results',
444
+ title: 'Survey results',
445
+ brief: 'Summarize the Harbor employee survey: a bar chart of satisfaction by department and a pie chart of preferred work setup.',
446
+ tier: 'untrusted',
447
+ mustInclude: ['layout-page', 'charts-bar', 'charts-pie'],
448
+ traps: [],
449
+ reference: page('Employee survey', 'Harbor, spring results', [
450
+ card('Satisfaction by department', [
451
+ cartesian('charts-bar', 'Satisfaction', 'Average satisfaction score by department, out of 5', [series('score', 'Score', ['Product', 'Support', 'Sales', 'Ops'], [4.2, 3.9, 4.0, 3.7])]),
452
+ ]),
453
+ card('Preferred work setup', [
454
+ partWhole('charts-pie', 'Work setup', 'Share of people preferring each setup', [
455
+ ['Hybrid', 58],
456
+ ['Remote', 31],
457
+ ['Office', 11],
458
+ ]),
459
+ ]),
460
+ ]),
461
+ },
462
+ {
463
+ id: 'g20-api-changelog',
464
+ title: 'API changelog',
465
+ brief: 'Write the Harbor API changelog entry for version 2024-06: added endpoints, deprecations, and a warning callout about the removal date.',
466
+ tier: 'untrusted',
467
+ mustInclude: ['layout-doc', 'blocks-text'],
468
+ traps: [],
469
+ reference: doc('API changelog: 2024-06', [
470
+ heading(2, 'Added'),
471
+ list(['`GET /v2/boards/{id}/activity`', '`POST /v2/exports`']),
472
+ heading(2, 'Deprecated'),
473
+ list(['`GET /v1/exports`, replaced by `POST /v2/exports`']),
474
+ callout('warning', 'Removal date', 'The v1 export endpoints stop responding on the fictional date of 1 December.'),
475
+ ]),
476
+ },
477
+ {
478
+ id: 'g21-event-agenda',
479
+ title: 'Event agenda',
480
+ brief: 'Show the agenda for the Pebble community day as a table of times, sessions and speakers, with a short intro.',
481
+ tier: 'untrusted',
482
+ mustInclude: ['layout-page', 'blocks-data'],
483
+ traps: [],
484
+ reference: page('Community day agenda', 'Pebble, 14 September', [
485
+ text('All sessions take place in the fictional Orchard Hall.'),
486
+ table('Agenda', [
487
+ ['time', 'Time'],
488
+ ['session', 'Session'],
489
+ ['speaker', 'Speaker'],
490
+ ], [
491
+ { time: '09:30', session: 'Welcome', speaker: 'Ada Brook' },
492
+ { time: '10:00', session: 'Boards at scale', speaker: 'Jonah Pike' },
493
+ { time: '11:15', session: 'Planning rituals', speaker: 'Mara Lind' },
494
+ ]),
495
+ ]),
496
+ },
497
+ {
498
+ id: 'g22-signup-sources',
499
+ title: 'Sign-up sources',
500
+ brief: 'Show how visitors flow from traffic sources to sign-up outcomes with a Sankey diagram.',
501
+ tier: 'untrusted',
502
+ mustInclude: ['layout-page', 'charts-sankey'],
503
+ traps: [],
504
+ reference: page('Sign-up sources', 'Pebble, last month', [
505
+ card('From source to outcome', [
506
+ node('charts-sankey', {
507
+ title: 'Visitor flow',
508
+ description: 'Visitors from each source to each sign-up outcome',
509
+ nodes: [
510
+ { id: 'search', label: 'Search' },
511
+ { id: 'referral', label: 'Referral' },
512
+ { id: 'signup', label: 'Signed up' },
513
+ { id: 'left', label: 'Left' },
514
+ ],
515
+ links: [
516
+ { source: 'search', target: 'signup', value: 120 },
517
+ { source: 'search', target: 'left', value: 380 },
518
+ { source: 'referral', target: 'signup', value: 90 },
519
+ { source: 'referral', target: 'left', value: 110 },
520
+ ],
521
+ }),
522
+ ]),
523
+ ]),
524
+ },
525
+ {
526
+ id: 'g23-activity-heatmap',
527
+ title: 'Activity heatmap',
528
+ brief: 'Show when the Harbor support team is busiest with a heatmap of tickets by weekday and time of day.',
529
+ tier: 'untrusted',
530
+ mustInclude: ['layout-page', 'charts-heatmap'],
531
+ traps: [],
532
+ reference: page('When we are busiest', 'Harbor support, last four weeks', [
533
+ card('Tickets by weekday and hour', [
534
+ node('charts-heatmap', {
535
+ title: 'Ticket volume',
536
+ description: 'Tickets by weekday and time of day',
537
+ cells: ['Mon', 'Tue', 'Wed'].flatMap((day, d) => ['Morning', 'Afternoon'].map((slot, s) => ({
538
+ x: day,
539
+ y: slot,
540
+ value: 20 + d * 7 + s * 11,
541
+ }))),
542
+ }),
543
+ ]),
544
+ ]),
545
+ },
546
+ {
547
+ id: 'g24-feature-adoption',
548
+ title: 'Feature adoption',
549
+ brief: 'Plot feature adoption against satisfaction for six Pebble features as a scatter chart.',
550
+ tier: 'untrusted',
551
+ mustInclude: ['layout-page', 'charts-scatter'],
552
+ traps: [],
553
+ reference: page('Feature adoption', 'Pebble, this quarter', [
554
+ card('Adoption and satisfaction', [
555
+ node('charts-scatter', {
556
+ title: 'Adoption against satisfaction',
557
+ description: 'Share of teams using each feature and their satisfaction score',
558
+ points: [
559
+ { id: 'templates', label: 'Templates', x: 62, y: 4.4 },
560
+ { id: 'shortcuts', label: 'Shortcuts', x: 35, y: 4.6 },
561
+ { id: 'export', label: 'Export', x: 48, y: 3.8 },
562
+ { id: 'comments', label: 'Comments', x: 81, y: 4.1 },
563
+ { id: 'timeline', label: 'Timeline', x: 27, y: 3.9 },
564
+ { id: 'search', label: 'Search', x: 74, y: 4.2 },
565
+ ],
566
+ }),
567
+ ]),
568
+ ]),
569
+ },
570
+ {
571
+ id: 'g25-quarter-goals',
572
+ title: 'Quarter goals',
573
+ brief: 'Show progress on three Harbor quarter goals as a grid of cards, each with a progress ring.',
574
+ tier: 'untrusted',
575
+ mustInclude: ['layout-grid', 'charts-progress-ring'],
576
+ traps: [],
577
+ reference: page('Quarter goals', 'Harbor, progress to date', [
578
+ grid(3, [
579
+ card('Reply time', [
580
+ node('charts-progress-ring', { label: 'Reply time goal', value: 72, max: 100 }),
581
+ ]),
582
+ card('Self-service', [
583
+ node('charts-progress-ring', { label: 'Self-service goal', value: 45, max: 100 }),
584
+ ]),
585
+ card('Hiring', [
586
+ node('charts-progress-ring', { label: 'Hiring goal', value: 90, max: 100 }),
587
+ ]),
588
+ ]),
589
+ ]),
590
+ },
591
+ {
592
+ id: 'g26-website-visitors',
593
+ title: 'Website visitors',
594
+ brief: 'Show website visitors per month for six months as an area chart, with the total as a stat.',
595
+ tier: 'untrusted',
596
+ mustInclude: ['layout-page', 'charts-area'],
597
+ traps: [],
598
+ reference: page('Website visitors', 'Pebble marketing site', [
599
+ stats([['Visitors, six months', '184,300']]),
600
+ card('Visitors per month', [
601
+ cartesian('charts-area', 'Monthly visitors', 'Visitors per month over six months', [
602
+ series('visitors', 'Visitors', MONTHS, [26400, 28100, 29800, 31200, 33300, 35500]),
603
+ ]),
604
+ ]),
605
+ ]),
606
+ },
607
+ {
608
+ id: 'g27-warehouse-kpis',
609
+ title: 'Warehouse KPIs',
610
+ brief: 'Build a warehouse dashboard for Harbor logistics: three KPIs (orders shipped, on-time rate, returns) and a combo chart of orders and returns per week.',
611
+ tier: 'untrusted',
612
+ mustInclude: ['layout-page', 'blocks-data', 'charts-combo'],
613
+ traps: [],
614
+ reference: page('Warehouse dashboard', 'Harbor logistics, six weeks', [
615
+ kpis([
616
+ ['Orders shipped', '12,480', '+6%'],
617
+ ['On-time rate', '97.2%', '+0.4 pt'],
618
+ ['Returns', '312', '-3%'],
619
+ ]),
620
+ card('Orders and returns', [
621
+ cartesian('charts-combo', 'Orders and returns', 'Orders shipped and returns per week', [
622
+ series('orders', 'Orders', WEEKS, [1980, 2040, 2110, 2060, 2150, 2140]),
623
+ series('returns', 'Returns', WEEKS, [52, 49, 55, 50, 54, 52]),
624
+ ]),
625
+ ]),
626
+ ]),
627
+ },
628
+ {
629
+ id: 'g28-newsletter',
630
+ title: 'Team newsletter',
631
+ brief: 'Write the June issue of the Pebble team newsletter: a cover photo, two short stories with headings, and a closing quote.',
632
+ tier: 'untrusted',
633
+ mustInclude: ['layout-doc', 'media-image', 'blocks-text'],
634
+ traps: [],
635
+ reference: doc('Pebble newsletter: June', [
636
+ image('images/newsletter-cover.webp', 'The Pebble team on the office roof garden'),
637
+ heading(2, 'Boards beta lands'),
638
+ text('Shared boards reached 400 fictional teams in the first week.'),
639
+ heading(2, 'Welcome, new teammates'),
640
+ text('Five people joined support and design this month.'),
641
+ quote('Small, steady releases keep us honest.', 'Ada Brook'),
642
+ ]),
643
+ },
644
+ {
645
+ id: 'g29-server-load',
646
+ title: 'Server load',
647
+ brief: 'Show current CPU, memory and disk use for the Harbor build server as three gauges in a grid.',
648
+ tier: 'untrusted',
649
+ mustInclude: ['layout-grid', 'charts-gauge'],
650
+ traps: [],
651
+ reference: page('Build server load', 'Harbor CI, right now', [
652
+ grid(3, [
653
+ card('CPU', [
654
+ node('charts-gauge', { label: 'CPU use in percent', value: 64, min: 0, max: 100 }),
655
+ ]),
656
+ card('Memory', [
657
+ node('charts-gauge', { label: 'Memory use in percent', value: 48, min: 0, max: 100 }),
658
+ ]),
659
+ card('Disk', [
660
+ node('charts-gauge', { label: 'Disk use in percent', value: 81, min: 0, max: 100 }),
661
+ ]),
662
+ ]),
663
+ ]),
664
+ },
665
+ {
666
+ id: 'g30-feature-announcement',
667
+ title: 'Feature announcement',
668
+ brief: 'Announce Pebble board templates: a hero image, a paragraph, three highlights as a list. Do not build a navigation menu or a sidebar section; the app shell already has them.',
669
+ tier: 'untrusted',
670
+ mustInclude: ['layout-page', 'media-image', 'blocks-text'],
671
+ traps: [NAVIGATION, CHROME],
672
+ reference: page('Board templates are here', 'Start every plan from a proven shape', [
673
+ image('images/templates-hero.webp', 'A board template with columns for goals, tasks and risks'),
674
+ text('Templates give every team the same starting structure, then get out of the way.'),
675
+ list([
676
+ 'Eight starter templates',
677
+ 'Save any board as a template',
678
+ 'Share templates across workspaces',
679
+ ]),
680
+ ]),
681
+ },
682
+ ]);
683
+ /** The task with `id`, or `undefined`. */
684
+ export function goldenTask(id) {
685
+ return GOLDEN_TASKS.find((task) => task.id === id);
686
+ }