@bongos/core 1.19.544 → 1.19.546
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.
- package/.bongos-core.json +87 -42
- package/docs/adr/0227-a-task-network-map-is-refused-the-goal-graph-is-the-map.md +115 -0
- package/docs/copy-inventory.md +42 -18
- package/docs/copy-registry.json +271 -25
- package/docs/module-api-changelog.md +4 -0
- package/docs/research/task-network-map/real-a-every-task.png +0 -0
- package/docs/research/task-network-map/real-b-dependency-forest.png +0 -0
- package/docs/research/task-network-map/real-c-goals.png +0 -0
- package/docs/research/task-network-map/real-d-joined-by-goal.png +0 -0
- package/modules/hall-ui/public/hall-kit.js +76 -41
- package/modules/hall-ui/public/profile-charts.js +8 -2
- package/modules/hall-ui/public/shell.js +30 -1
- package/modules/hall-ui/public/studio.css +268 -0
- package/modules/hall-ui/public/studio.html +74 -0
- package/modules/hall-ui/public/studio.js +213 -0
- package/modules/hall-ui/public/studio.states.json +54 -0
- package/modules/hall-ui/public/style.css +9 -0
- package/modules/ui-design/skills/brandkit/SKILL.md +5 -1
- package/modules/ui-design/skills/design-taste-frontend/SKILL.md +5 -1
- package/modules/ui-design/skills/design-taste-frontend-v1/SKILL.md +5 -1
- package/modules/ui-design/skills/gpt-taste/SKILL.md +5 -1
- package/modules/ui-design/skills/high-end-visual-design/SKILL.md +5 -1
- package/modules/ui-design/skills/image-to-code/SKILL.md +5 -1
- package/modules/ui-design/skills/imagegen-frontend-mobile/SKILL.md +5 -1
- package/modules/ui-design/skills/imagegen-frontend-web/SKILL.md +5 -1
- package/modules/ui-design/skills/impeccable/SKILL.md +5 -1
- package/modules/ui-design/skills/industrial-brutalist-ui/SKILL.md +5 -1
- package/modules/ui-design/skills/minimalist-ui/SKILL.md +5 -1
- package/modules/ui-design/skills/redesign-existing-projects/SKILL.md +5 -1
- package/modules/ui-design/skills/stitch-design-taste/SKILL.md +5 -1
- package/modules/ui-design/skills/style/SKILL.md +5 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/fitness.js +10 -3
- package/scripts/gds/skill-lint.js +43 -9
- package/scripts/gds/spike-task-map.js +178 -9
- package/src/bongos/serve-internal.js +1 -1
- package/src/module-api.js +1 -1
- package/tests/hall_kit_charts.mjs +59 -0
- package/tests/hall_nav.mjs +6 -1
- package/tests/hall_page_gate_map.mjs +5 -0
- package/tests/hall_studio_world.mjs +143 -0
- package/tests/skill_lint.mjs +51 -2
- package/tests/spike_task_map.mjs +0 -0
- package/tests/ui_design_skills.mjs +12 -2
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// modules/hall-ui/public/studio.js — the Studio (artist mode), /builders/studio.
|
|
2
|
+
// R06 of goal 1000074 (the artist's loop), task 1003117.
|
|
3
|
+
//
|
|
4
|
+
// The criterion (artist-mode): "a place an artist wants to be, not a form. A
|
|
5
|
+
// focus environment on the Cloud Bongos screen — a lofi-girl-style zen garden of
|
|
6
|
+
// focus and creativity — rather than another table of rows."
|
|
7
|
+
//
|
|
8
|
+
// So this is NOT a queue table. It aggregates the artist's real work — the two
|
|
9
|
+
// surfaces the rest of goal 1000074 built — and presents it ONE PIECE AT A TIME,
|
|
10
|
+
// a stone to tend in a calm garden, with the rest waiting quietly:
|
|
11
|
+
// 1. REVIEW REQUESTS (R04, cascade.js) — a copy/visual ship files a two-step
|
|
12
|
+
// artist review at `backlog`, discipline 'artist', source 'cascade'. The
|
|
13
|
+
// two steps (coach the grader, then remake/tweak) live on the task record;
|
|
14
|
+
// this room names them and opens the door.
|
|
15
|
+
// 2. FLAGGED COPY (R02, copy-desk) — open flags over the words the product
|
|
16
|
+
// shows people. Best-effort: an instance without the copy-desk module has
|
|
17
|
+
// no queue, and the room degrades to reviews alone rather than erroring.
|
|
18
|
+
//
|
|
19
|
+
// It writes NOTHING and gates NOTHING (ADR 0162 / the goal's no-live-CMS rule):
|
|
20
|
+
// "open this" routes to where the craft is actually done (the task record, the
|
|
21
|
+
// copy desk), and "let it be for now" only advances the reader to the next
|
|
22
|
+
// piece. The full tables it replaces stay one link away in the footer.
|
|
23
|
+
|
|
24
|
+
(() => {
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const API = '/api/bongos';
|
|
28
|
+
const api = window.BongosClient.createClient({ baseUrl: '', credentials: 'same-origin', throwOnError: false });
|
|
29
|
+
const { escapeHtml, $ } = window.OTB;
|
|
30
|
+
|
|
31
|
+
let viewer = null;
|
|
32
|
+
let pieces = []; // the combined garden: [{ type:'review'|'flag', … }]
|
|
33
|
+
let idx = 0; // which stone is in focus
|
|
34
|
+
|
|
35
|
+
// Bound the reviews read. cascade.js files a review per qualifying ship and they
|
|
36
|
+
// sit at backlog until claimed or dismissed ("dismissable rather than nagging"),
|
|
37
|
+
// so this queue grows without bound over the project's life — the unbounded-read
|
|
38
|
+
// shape modules/hall-ui/CLAUDE.md flags as a repeat bug (the Work board's backlog,
|
|
39
|
+
// Home's next-up card, the Goals rollup all had it). 50 is far more than a focus
|
|
40
|
+
// queue tends at once; the footer links to the copy desk and board are the
|
|
41
|
+
// whole-list path. listTasks orders `priority NULLS LAST, created_at`, so the cap
|
|
42
|
+
// keeps the most-prioritised waiting reviews.
|
|
43
|
+
const REVIEW_LIMIT = 50;
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// helpers
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
function greeting() {
|
|
50
|
+
const h = new Date().getHours();
|
|
51
|
+
if (h < 5) return 'Still up';
|
|
52
|
+
if (h < 12) return 'Good morning';
|
|
53
|
+
if (h < 18) return 'Good afternoon';
|
|
54
|
+
return 'Good evening';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// The shipped task a review is ABOUT — cascade.js stamps
|
|
58
|
+
// source_ref = 'cascade-artist-review-on-ship-<taskId>'.
|
|
59
|
+
function reviewShippedId(t) {
|
|
60
|
+
const m = /-on-ship-(\d+)/.exec(t.source_ref || '');
|
|
61
|
+
return m ? m[1] : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The product's own words, shown as evidence — untrusted source-tree text, so
|
|
65
|
+
// escaped, and clipped so one runaway string cannot fill the room.
|
|
66
|
+
function quote(text, max = 300) {
|
|
67
|
+
const s = String(text == null ? '' : text);
|
|
68
|
+
return escapeHtml(s.length > max ? `${s.slice(0, max)}…` : s);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Clip a plain field (a name, a reason) so one very long value cannot stretch
|
|
72
|
+
// the card — the mirror of quote()'s clip, for text that is not the evidence.
|
|
73
|
+
// Escaping still happens at render; this only bounds length.
|
|
74
|
+
function clip(text, max) {
|
|
75
|
+
const s = String(text == null ? '' : text);
|
|
76
|
+
return s.length > max ? `${s.slice(0, max)}…` : s;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// the focus card, one shape per kind of work
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
function reviewCard(p, n) {
|
|
84
|
+
const title = p.shippedId
|
|
85
|
+
? `The copy and visuals that shipped in task #${escapeHtml(p.shippedId)}`
|
|
86
|
+
: escapeHtml(p.title || 'A review of what shipped');
|
|
87
|
+
return `
|
|
88
|
+
<p class="studio-card__eyebrow">to tend now · ${escapeHtml(n)}</p>
|
|
89
|
+
<h2 class="studio-card__title">${title}</h2>
|
|
90
|
+
<p class="studio-card__context">It shipped and it is live. Your review coaches the grader on how it judged the work, then remakes or tweaks the words or art only if they need it — it never blocks what shipped.</p>
|
|
91
|
+
<ol class="studio-steps">
|
|
92
|
+
<li class="studio-step"><span class="studio-step__n">01</span><span>Coach the grader<small>Review how it judged this work, and teach it what good looked like.</small></span></li>
|
|
93
|
+
<li class="studio-step"><span class="studio-step__n">02</span><span>Remake or tweak<small>Only if it needs it — with the AI at your side, or on your own.</small></span></li>
|
|
94
|
+
</ol>
|
|
95
|
+
<div class="studio-card__actions">
|
|
96
|
+
<a class="btn-accent" href="/builders/task/${escapeHtml(String(p.taskId))}">Open this review</a>
|
|
97
|
+
<button type="button" class="btn-ghost" data-skip>Let it be for now</button>
|
|
98
|
+
</div>`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function flagCard(p, n) {
|
|
102
|
+
const who = p.who ? `${escapeHtml(p.who)} flagged this` : 'Someone flagged this';
|
|
103
|
+
const reason = p.reason ? ` — ${escapeHtml(p.reason)}` : '';
|
|
104
|
+
return `
|
|
105
|
+
<p class="studio-card__eyebrow">to tend now · ${escapeHtml(n)}</p>
|
|
106
|
+
<blockquote class="studio-card__quote">${quote(p.text)}</blockquote>
|
|
107
|
+
<p class="studio-card__context">${who}${reason}</p>
|
|
108
|
+
<div class="studio-card__actions">
|
|
109
|
+
<a class="btn-accent" href="/builders/copy-desk">Open in the copy desk</a>
|
|
110
|
+
<button type="button" class="btn-ghost" data-skip>Let it be for now</button>
|
|
111
|
+
</div>`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function emptyCard(done) {
|
|
115
|
+
const heading = done ? 'You have tended everything waiting' : 'Nothing waits right now';
|
|
116
|
+
const body = done
|
|
117
|
+
? 'That is the whole garden. Come back when work ships, or start again from the top.'
|
|
118
|
+
: 'A quiet moment — either good news or an unread queue. When work with copy or visuals ships, a review appears here for you.';
|
|
119
|
+
const restart = done
|
|
120
|
+
? '<div class="studio-card__actions studio-empty__actions"><button type="button" class="btn-ghost" data-restart>Start over</button></div>'
|
|
121
|
+
: '';
|
|
122
|
+
return `<div class="studio-empty"><h2>${heading}</h2><p>${body}</p>${restart}</div>`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// paint
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
|
|
129
|
+
function paintHead() {
|
|
130
|
+
const name = viewer && (viewer.display_name || viewer.github_login);
|
|
131
|
+
$('#studio-greet').textContent = name ? `${greeting()}, ${name}` : greeting();
|
|
132
|
+
const n = pieces.length;
|
|
133
|
+
$('#studio-sub').textContent = n
|
|
134
|
+
? `${n} ${n === 1 ? 'piece' : 'pieces'} of the product's voice ${n === 1 ? 'waits' : 'wait'} for you. Tend them one at a time — or let them be.`
|
|
135
|
+
: 'Nothing waits right now. Enjoy the quiet.';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function paint() {
|
|
139
|
+
const focus = $('#studio-focus');
|
|
140
|
+
const rest = $('#studio-rest');
|
|
141
|
+
|
|
142
|
+
if (!pieces.length) { focus.innerHTML = emptyCard(false); rest.hidden = true; return; }
|
|
143
|
+
if (idx >= pieces.length) { focus.innerHTML = emptyCard(true); rest.hidden = true; return; }
|
|
144
|
+
|
|
145
|
+
const p = pieces[idx];
|
|
146
|
+
focus.innerHTML = p.type === 'review' ? reviewCard(p, `${idx + 1} of ${pieces.length}`) : flagCard(p, `${idx + 1} of ${pieces.length}`);
|
|
147
|
+
|
|
148
|
+
// The rest of the garden: one stone per remaining piece, quiet and
|
|
149
|
+
// non-interactive — the room asks the reader to tend one thing, not to scan.
|
|
150
|
+
const remaining = pieces.length - (idx + 1);
|
|
151
|
+
if (remaining > 0) {
|
|
152
|
+
const shown = Math.min(remaining, 14);
|
|
153
|
+
const stones = new Array(shown).fill('<span class="studio-stone"></span>').join('');
|
|
154
|
+
const extra = remaining > shown ? ` +${remaining - shown}` : '';
|
|
155
|
+
rest.innerHTML = `<span class="studio-stones" aria-hidden="true">${stones}</span>`
|
|
156
|
+
+ `<span class="studio-rest__line">and ${remaining} more waiting${extra}</span>`;
|
|
157
|
+
rest.hidden = false;
|
|
158
|
+
} else {
|
|
159
|
+
rest.hidden = true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// load
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
|
|
167
|
+
// The waiting review requests: backlog is where cascade.js files them and where
|
|
168
|
+
// they sit until claimed or dismissed ("dismissable rather than nagging"), so
|
|
169
|
+
// status=backlog is the bounded, correct read for what is waiting to be tended.
|
|
170
|
+
async function loadReviews() {
|
|
171
|
+
const res = await api.request('GET', `${API}/tasks?discipline=artist&status=backlog&limit=${REVIEW_LIMIT}`);
|
|
172
|
+
if (!res.ok) return [];
|
|
173
|
+
const tasks = (res.data && res.data.tasks) || [];
|
|
174
|
+
return tasks
|
|
175
|
+
.filter((t) => t.source === 'cascade' || /^artist review\b/i.test(t.title || ''))
|
|
176
|
+
.sort((a, b) => new Date(b.created_at || 0) - new Date(a.created_at || 0))
|
|
177
|
+
.map((t) => ({ type: 'review', taskId: t.id, title: t.title, shippedId: reviewShippedId(t) }));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// The open flags. Best-effort: no copy-desk module → 404 → no flags, and the
|
|
181
|
+
// room is reviews alone rather than an error.
|
|
182
|
+
async function loadFlags() {
|
|
183
|
+
const res = await api.request('GET', `${API}/copy-desk/queue?status=open`);
|
|
184
|
+
if (!res.ok) return [];
|
|
185
|
+
// The server already filters to open flags (?status=open); no client re-filter.
|
|
186
|
+
const flags = (res.data && res.data.flags) || [];
|
|
187
|
+
return flags.map((f) => ({
|
|
188
|
+
type: 'flag',
|
|
189
|
+
text: f.scope === 'surface' ? f.surface : (f.current ? f.current.text : f.text_at_flag),
|
|
190
|
+
reason: clip(f.reason, 240),
|
|
191
|
+
who: clip(f.flagged_by_name || f.flagged_by_login || '', 60) || null,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// wire + boot
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
document.addEventListener('click', (ev) => {
|
|
200
|
+
if (ev.target.closest('[data-skip]')) { idx += 1; paint(); window.scrollTo({ top: 0 }); return; }
|
|
201
|
+
if (ev.target.closest('[data-restart]')) { idx = 0; paint(); window.scrollTo({ top: 0 }); }
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
(async () => {
|
|
205
|
+
const me = await api.request('GET', `${API}/me`);
|
|
206
|
+
if (me.ok) viewer = me.data.builder || me.data;
|
|
207
|
+
// Reviews first (the richer craft), then flags — each newest-first within.
|
|
208
|
+
const [reviews, flags] = await Promise.all([loadReviews(), loadFlags()]);
|
|
209
|
+
pieces = [...reviews, ...flags];
|
|
210
|
+
paintHead();
|
|
211
|
+
paint();
|
|
212
|
+
})();
|
|
213
|
+
})();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "The Studio (artist mode), R06 of goal 1000074 (task 1003117). A calm room that surfaces the artist's real work — backlog review requests (cascade, R04) and open copy flags (R02) — one piece at a time, never a table. Against the kit's own stub the page renders its EMPTY state (no /tasks or /copy-desk feed), which is a state the floors must hold in; against the hall-preview harness with the studio__reviews / copy-desk__queue fixtures it renders the focus card and the garden's stones.",
|
|
3
|
+
"page": "/builders/studio",
|
|
4
|
+
"surface": "hall-ui",
|
|
5
|
+
"stub": {
|
|
6
|
+
"prefix": "/builders/"
|
|
7
|
+
},
|
|
8
|
+
"modeQuery": false,
|
|
9
|
+
"ignoreRequests": [
|
|
10
|
+
"/api/(gds|bongos)/me$",
|
|
11
|
+
"/api/(gds|bongos)/me/",
|
|
12
|
+
"/api/(gds|bongos)/tasks",
|
|
13
|
+
"/api/(gds|bongos)/copy-desk/"
|
|
14
|
+
],
|
|
15
|
+
"ignoreConsole": [
|
|
16
|
+
"/api/(gds|bongos)/",
|
|
17
|
+
"\\b401\\b",
|
|
18
|
+
"\\b403\\b",
|
|
19
|
+
"\\b404\\b",
|
|
20
|
+
"\\b501\\b",
|
|
21
|
+
"Unauthorized",
|
|
22
|
+
"Forbidden",
|
|
23
|
+
"Not Found",
|
|
24
|
+
"load failed"
|
|
25
|
+
],
|
|
26
|
+
"states": {
|
|
27
|
+
"focus": {
|
|
28
|
+
"auth": true,
|
|
29
|
+
"actions": [
|
|
30
|
+
[
|
|
31
|
+
"wait",
|
|
32
|
+
700
|
|
33
|
+
]
|
|
34
|
+
],
|
|
35
|
+
"expect": {
|
|
36
|
+
"visible": [
|
|
37
|
+
"#studio-focus"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"out": {
|
|
42
|
+
"auth": false
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"reducedMotion": {
|
|
46
|
+
"auth": true,
|
|
47
|
+
"actions": [
|
|
48
|
+
[
|
|
49
|
+
"wait",
|
|
50
|
+
600
|
|
51
|
+
]
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -658,6 +658,15 @@ main:focus { outline: none; }
|
|
|
658
658
|
.nav-item__label { display: none; font-size: 14px; }
|
|
659
659
|
.nav-icon { width: 16px; height: 16px; flex-shrink: 0; }
|
|
660
660
|
|
|
661
|
+
/* task 1003117 (R06 of goal 1000074): the Studio entry is warmed for a builder
|
|
662
|
+
whose craft is artist — the "emphasized entry for artist-craft builders" half
|
|
663
|
+
of artist mode. Distinct from --active (the current page's leading accent bar):
|
|
664
|
+
this warms the GLYPH, so the emphasis reads in the collapsed icon-only rail
|
|
665
|
+
too. accent-ink is the text-safe accent in both modes. shell.js sets the class
|
|
666
|
+
from /me's preferred_disciplines; it is cosmetic (the page is open to all). */
|
|
667
|
+
.nav-item--craft .nav-icon,
|
|
668
|
+
.nav-item--craft .nav-item__label { color: var(--accent-ink); }
|
|
669
|
+
|
|
661
670
|
.app-sidebar__foot {
|
|
662
671
|
padding: 10px 0;
|
|
663
672
|
border-top: 1px solid var(--glass-edge);
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: brandkit
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The identity-system method for any instance, under the owner's hero-only rule. Infers the brand strategy
|
|
5
|
+
first, holds the logo standard and the five concept methods, and lands the system as the instance's own
|
|
6
|
+
materials — the mark as SVG, the colours as the pack, the type as its faces. Triggers on "brand kit",
|
|
7
|
+
"identity system", "logo system". Never generates a logo, wordmark or UI mockup.
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: design-taste-frontend
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The default taste skill for a landing page, portfolio or marketing surface on any Cloud Bongos instance.
|
|
5
|
+
Says the design read in one line, sets three dials (variance, motion, density), locks one world for the
|
|
6
|
+
whole page, and ends on a pre-flight the kit measures. Triggers on "design a landing page", "make this not
|
|
7
|
+
look templated", "taste pass", "anti-slop". Not for dashboards or native mobile.
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: design-taste-frontend-v1
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The earlier generation of the taste skill, kept under its own name so a task or builder that asks for it
|
|
5
|
+
gets exactly this behaviour while the default (design-taste-frontend) evolves separately. A fixed triple of
|
|
6
|
+
dials, the layout bans, full interaction cycles, and a named vocabulary of premium patterns. Triggers on
|
|
7
|
+
"design-taste-frontend-v1", "the fixed dials", "the pattern vocabulary".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gpt-taste
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Anti-default enforcement for a persuasive scrolling surface when the last attempt came out looking like
|
|
5
|
+
every other one. A written plan block before any markup, derived deterministically from the route; the
|
|
6
|
+
four-stage attention-interest-desire-action structure; an ultra-wide hero; a dense tile grid with zero empty
|
|
7
|
+
cells. Triggers on "it looks generic", "award-tier", "anti-default".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: high-end-visual-design
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Makes an interface read as an expensive agency build, inside the instance's world. One texture archetype and
|
|
5
|
+
one layout archetype per project, the container anatomy, the pill button, the spatial rhythm, the motion
|
|
6
|
+
choreography inside the Kill Switch, the mobile collapse, then a pre-output checklist. Triggers on "make it
|
|
7
|
+
feel premium", "agency-grade", "this looks cheap", "the polish pass".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: image-to-code
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The analyse-then-implement loop for visually important web work, under the owner's hero-only rule. The
|
|
5
|
+
design source of truth is the owner's reference images and the instance's world, read per image and
|
|
6
|
+
extracted into a full spec before a line is written. Triggers on "build this from the reference", "implement
|
|
7
|
+
the mock faithfully". Never generates a section, comp or screen.
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: imagegen-frontend-mobile
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The plate-making skill for the narrow end of a web surface, under the owner's hero-only rule. Text-free
|
|
5
|
+
portrait plates and hero objects for the 390 and 320 compositions the kit renders, sized for the fold and
|
|
6
|
+
clear of what a phone reserves, with a sidecar beside every file. Triggers on "a plate for the mobile hero",
|
|
7
|
+
"the masthead at 390". Never a screen, a phone mockup or code.
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: imagegen-frontend-web
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The plate-making skill for a web surface, under the owner's hero-only rule. Text-free hero plates, hero
|
|
5
|
+
objects and atmosphere backdrops for the slots a composition already has — never one per section, never a
|
|
6
|
+
screen, never a UI comp, and no page code. One material, light and camera across the family, landed with a
|
|
7
|
+
provenance sidecar. Triggers on "make a hero plate", "an atmosphere backdrop".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: impeccable
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
The design-craft method for any surface, invoked as one skill plus an optional sub-command and target
|
|
5
|
+
("impeccable audit /projects"). Sixteen playbooks — shape, audit, critique, polish, harden, animate,
|
|
6
|
+
typeset, colorize, layout, adapt, distill, clarify, onboard, optimize, document, extract — one per request.
|
|
7
|
+
Triggers on "impeccable", "critique this page", "audit the UI". Web surfaces only.
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: industrial-brutalist-ui
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Raw mechanical interfaces that read like a technical document, inside the instance's world. One archetype
|
|
5
|
+
per project (Swiss industrial print or dark tactical terminal, never mixed), massive uppercase display
|
|
6
|
+
against tracked-out mono metadata, strict grid anchoring, zero corner rounding, halftone and scanline
|
|
7
|
+
degradation inside the Kill Switch. Triggers on "brutalist", "industrial", "make it raw".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: minimalist-ui
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Quiet editorial product interfaces built out of type and white space, inside the instance's world. Macro
|
|
5
|
+
whitespace first, a capped measure, one display job and one body job, exactly one hairline weight for every
|
|
6
|
+
border, flat tile cards with no shadow, entry motion inside the Kill Switch. Triggers on "make it minimal",
|
|
7
|
+
"clean and editorial", "this feels busy". Declines dense surfaces.
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: redesign-existing-projects
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Upgrades an existing site or app in place, in whatever framework and styling method it already uses, without
|
|
5
|
+
breaking it. Three fixed steps — scan the stack, diagnose against a written audit, apply targeted fixes —
|
|
6
|
+
with the instance's world as the answer key and a fixed impact-per-risk fix order. Triggers on "redesign
|
|
7
|
+
this", "upgrade the existing page", "audit this UI".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stitch-design-taste
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Writes a design contract document for an external screen-generating tool such as Google Stitch, in the
|
|
5
|
+
platform's own frontmatter shape. Four dials with named bands and stated defaults, then eight fixed sections
|
|
6
|
+
pairing descriptive language with exact values. The thirteen colours are transcribed from the instance's
|
|
7
|
+
pack, never invented. Triggers on "a design brief for Stitch".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: style
|
|
3
|
-
description:
|
|
3
|
+
description: >-
|
|
4
|
+
Runs a bounded session in which an owner authors their own look for the instance, as a branding pack inside
|
|
5
|
+
the fifteen-token contract, and proves it clean before it lands. Four steps and no more — SEARCH, CREATE,
|
|
6
|
+
PROVE, ADOPT. Triggers on "/style", "make a look", "author a style", "I want our own theme", "add a style to
|
|
7
|
+
the library".
|
|
4
8
|
---
|
|
5
9
|
|
|
6
10
|
<!-- BEGIN PLATFORM PREAMBLE · ui-design module · one block, byte-identical in every skill the module ships (vendored or rebuilt in-house) so an upstream refresh is a three-way merge; the source is modules/ui-design/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.546",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.546",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.546",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
package/scripts/gds/fitness.js
CHANGED
|
@@ -1311,7 +1311,11 @@ function checkErrorEnvelope() {
|
|
|
1311
1311
|
// truncated EVERY field, the skill matched on its body text, and nothing in CI noticed. A parse
|
|
1312
1312
|
// error is a hard fail; description length and the listing budget are advisory (the listing is
|
|
1313
1313
|
// resident in every session, ~1% of context, and gets truncated past ~8k chars). The check reads
|
|
1314
|
-
// the instance's .claude/skills/
|
|
1314
|
+
// every skill Claude Code can load — the instance's .claude/skills/ AND the module-owned
|
|
1315
|
+
// modules/*/skills/ that claude-materialize.js copies into it (task 1003587: scanning only the
|
|
1316
|
+
// tracked root meant 14 ui-design skills went unlinted until the untracked copy existed, so four
|
|
1317
|
+
// unparseable frontmatters shipped and fitness only went red on a checkout that had materialized).
|
|
1318
|
+
// A quiet pass when a checkout carries none (published core).
|
|
1315
1319
|
function checkSkillFrontmatter() {
|
|
1316
1320
|
const violations = [];
|
|
1317
1321
|
const warnings = [];
|
|
@@ -1329,7 +1333,10 @@ function checkSkillFrontmatter() {
|
|
|
1329
1333
|
}
|
|
1330
1334
|
if (long.length) {
|
|
1331
1335
|
long.sort((a, b) => b.n - a.n);
|
|
1332
|
-
|
|
1336
|
+
// The skill's own name is its PARENT dir — a fixed path index would read "skills"
|
|
1337
|
+
// for a module-owned path (modules/<key>/skills/<name>/SKILL.md).
|
|
1338
|
+
const skillName = (f) => f.split('/').slice(-2, -1)[0] || f;
|
|
1339
|
+
warnings.push(`${long.length} description(s) over ${lint.DESC_WARN_CHARS} chars (longest: ${long.slice(0, 4).map((l) => `${skillName(l.file)} ${l.n}`).join(', ')}) — every char is resident in every session; run node scripts/gds/skill-lint.js.`);
|
|
1333
1340
|
}
|
|
1334
1341
|
if (report.overBudget) warnings.push(`the skill listing is ${report.listingChars} chars (~${estTokens(report.listingChars)} tokens) against a ~${report.budgetChars}-char budget — Claude Code truncates entries past it and routing degrades.`);
|
|
1335
1342
|
return {
|
|
@@ -1338,7 +1345,7 @@ function checkSkillFrontmatter() {
|
|
|
1338
1345
|
hardFail: violations.length > 0,
|
|
1339
1346
|
violations,
|
|
1340
1347
|
warnings,
|
|
1341
|
-
note: `${report.results.length} SKILL.md file(s) under .claude/skills/ parse as YAML (name + description present, no ": " / " #" in a plain scalar); length + listing budget advisory.`,
|
|
1348
|
+
note: `${report.results.length} SKILL.md file(s) under .claude/skills/ + modules/*/skills/ parse as YAML (name + description present, no ": " / " #" in a plain scalar); length + listing budget advisory.`,
|
|
1342
1349
|
};
|
|
1343
1350
|
}
|
|
1344
1351
|
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
// verdict as authoritative over this one.
|
|
24
24
|
//
|
|
25
25
|
// Usage:
|
|
26
|
-
// node scripts/gds/skill-lint.js lint every
|
|
26
|
+
// node scripts/gds/skill-lint.js lint every skill Claude Code can load — .claude/skills/*
|
|
27
|
+
// plus the module-owned modules/*/skills/* that materialize
|
|
28
|
+
// into it; exit 1 on any error
|
|
27
29
|
// node scripts/gds/skill-lint.js <file...> lint specific files
|
|
28
30
|
// node scripts/gds/skill-lint.js --hook PostToolUse mode: read the hook JSON on stdin, lint the
|
|
29
31
|
// edited file if it is a SKILL.md, print findings, exit 0
|
|
@@ -108,14 +110,40 @@ function lintSkillFile(text, { file = 'SKILL.md' } = {}) {
|
|
|
108
110
|
return res;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
// Every SKILL.md
|
|
112
|
-
function
|
|
113
|
-
const dir = path.join(root, '.claude', 'skills');
|
|
113
|
+
// Every SKILL.md in one skills root (one level deep, plus a `vendor/` tier).
|
|
114
|
+
function skillsIn(dir) {
|
|
114
115
|
if (!fs.existsSync(dir)) return [];
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.
|
|
116
|
+
const out = [];
|
|
117
|
+
for (const d of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
118
|
+
if (!d.isDirectory()) continue;
|
|
119
|
+
const own = path.join(dir, d.name, 'SKILL.md');
|
|
120
|
+
if (fs.existsSync(own)) { out.push(own); continue; }
|
|
121
|
+
if (d.name === 'vendor') out.push(...skillsIn(path.join(dir, d.name)));
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Every skill Claude Code can end up loading — the tracked `.claude/skills/` PLUS the
|
|
127
|
+
// module-owned `modules/<key>/skills/`, because claude-materialize.js copies those into
|
|
128
|
+
// `.claude/skills/` as untracked copies (task 1003330) and a defect in one only shows up
|
|
129
|
+
// after materialization. Scanning only the tracked root left 14 ui-design skills unlinted
|
|
130
|
+
// until the copy existed, which is exactly how four unparseable frontmatters shipped
|
|
131
|
+
// (task 1003587). A name already present in `.claude/skills/` wins and its module copy is
|
|
132
|
+
// skipped — the same precedence the materializer applies — so nothing is counted twice.
|
|
133
|
+
function listSkillFiles(root = REPO_ROOT) {
|
|
134
|
+
const core = skillsIn(path.join(root, '.claude', 'skills'));
|
|
135
|
+
const seen = new Set(core.map((f) => path.basename(path.dirname(f))));
|
|
136
|
+
const modulesDir = path.join(root, 'modules');
|
|
137
|
+
const owned = [];
|
|
138
|
+
if (fs.existsSync(modulesDir)) {
|
|
139
|
+
for (const d of fs.readdirSync(modulesDir, { withFileTypes: true })) {
|
|
140
|
+
if (!d.isDirectory()) continue;
|
|
141
|
+
for (const f of skillsIn(path.join(modulesDir, d.name, 'skills'))) {
|
|
142
|
+
if (!seen.has(path.basename(path.dirname(f)))) owned.push(f);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return [...core, ...owned];
|
|
119
147
|
}
|
|
120
148
|
|
|
121
149
|
// Lint a set of files; returns per-file results plus the listing total vs budget.
|
|
@@ -125,7 +153,13 @@ function lintSkills(files) {
|
|
|
125
153
|
return { results, listingChars, budgetChars: LISTING_BUDGET_CHARS, overBudget: listingChars > LISTING_BUDGET_CHARS };
|
|
126
154
|
}
|
|
127
155
|
|
|
128
|
-
|
|
156
|
+
// The PostToolUse hook's gate. It must match a module-owned SKILL.md too — that is the
|
|
157
|
+
// file a builder actually edits; the `.claude/skills/` copy is generated (task 1003587).
|
|
158
|
+
function isSkillMd(p) {
|
|
159
|
+
const s = String(p || '');
|
|
160
|
+
return /[\\/]\.claude[\\/]skills[\\/](?:vendor[\\/])?[^\\/]+[\\/]SKILL\.md$/.test(s)
|
|
161
|
+
|| /[\\/]modules[\\/][^\\/]+[\\/]skills[\\/](?:vendor[\\/])?[^\\/]+[\\/]SKILL\.md$/.test(s);
|
|
162
|
+
}
|
|
129
163
|
|
|
130
164
|
function format(report, { relTo = REPO_ROOT } = {}) {
|
|
131
165
|
const out = [];
|