@bongos/core 1.19.459 → 1.19.461
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 +65 -35
- package/.claude/skills/design/SKILL.md +10 -3
- package/docs/adr/0220-an-in-house-rebuilt-skill-is-a-first-party-skill.md +46 -0
- package/docs/adr/README.md +1 -0
- package/docs/copy-inventory.md +52 -61
- package/docs/copy-registry.json +92 -203
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/collab-lib.js +40 -4
- package/modules/hall-ui/public/collab.css +18 -34
- package/modules/hall-ui/public/collab.html +17 -17
- package/modules/hall-ui/public/collab.js +75 -39
- package/modules/hall-ui/public/collab.states.json +2 -2
- package/modules/hall-ui/public/copy-desk.css +64 -109
- package/modules/hall-ui/public/copy-desk.html +76 -69
- package/modules/hall-ui/public/copy-desk.js +175 -80
- package/modules/hall-ui/public/copy-desk.states.json +59 -2
- package/modules/hall-ui/public/oversight.css +11 -2
- package/modules/lifecycle/help-requests.js +18 -8
- package/modules/ui-design/module.json +1 -1
- package/modules/ui-design/skills/PREAMBLE.md +3 -3
- package/modules/ui-design/skills/README.md +13 -0
- package/modules/ui-design/skills/design-taste-frontend/SKILL.md +136 -0
- package/modules/ui-design/skills/design-taste-frontend-v1/SKILL.md +125 -0
- package/modules/ui-design/skills/high-end-visual-design/SKILL.md +128 -0
- package/modules/ui-design/skills/redesign-existing-projects/SKILL.md +120 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/docs-entropy.js +5 -1
- package/src/module-api.js +1 -1
- package/tests/collab_page.mjs +13 -7
- package/tests/docs_entropy.mjs +29 -1
- package/tests/hall_collab_world.mjs +214 -0
- package/tests/ui_design_skills.mjs +99 -9
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
// opens with the PLATFORM PREAMBLE byte-identical to PREAMBLE.md; every name the manifest
|
|
5
5
|
// contributes resolves to a real skill dir; a module-owned skill reaches a builder's
|
|
6
6
|
// materialised .claude/skills with its sidecar (and not when the module is off); /design
|
|
7
|
-
// lists every vendored skill by name; the policy ADR is indexed.
|
|
7
|
+
// lists every vendored skill by name; the policy ADR is indexed. Since task 1003325 (ADR
|
|
8
|
+
// 0220) the same file pins the IN-HOUSE rebuilds under skills/<name>/: the same preamble
|
|
9
|
+
// first and once, a `## Rebuilt from` section instead of a sidecar (the spec task, ADR
|
|
10
|
+
// 0198, "no upstream bytes"), the style library named as the palette source, no image
|
|
11
|
+
// mandate, and the preamble copies proven not to be doc-entropy debt. DB-free.
|
|
8
12
|
import assert from 'node:assert/strict';
|
|
9
13
|
import { test } from 'node:test';
|
|
10
14
|
import { createRequire } from 'node:module';
|
|
@@ -93,6 +97,85 @@ test('every vendored SKILL.md opens with the PLATFORM PREAMBLE, byte-identical t
|
|
|
93
97
|
}
|
|
94
98
|
});
|
|
95
99
|
|
|
100
|
+
// ── every in-house rebuild: the preamble, the Rebuilt-from section, no sidecar (ADR 0220) ──
|
|
101
|
+
const TASTE_CORE = ['design-taste-frontend', 'design-taste-frontend-v1', 'high-end-visual-design', 'redesign-existing-projects'];
|
|
102
|
+
|
|
103
|
+
test('the taste core of task 1003325 exists as four in-house skills and every one is declared', () => {
|
|
104
|
+
for (const name of TASTE_CORE) {
|
|
105
|
+
assert.ok(ownDirs.includes(name), `${name}: skills/${name}/SKILL.md exists`);
|
|
106
|
+
assert.ok(manifest.contributes.skills.includes(name), `${name}: declared in contributes.skills`);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('every in-house SKILL.md opens with the PLATFORM PREAMBLE, byte-identical to PREAMBLE.md, exactly once, right after its frontmatter', () => {
|
|
111
|
+
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
112
|
+
for (const name of ownDirs) {
|
|
113
|
+
const text = read(path.join(SKILLS, name, 'SKILL.md'));
|
|
114
|
+
const fm = text.match(/^---\n[\s\S]*?\n---\n/);
|
|
115
|
+
assert.ok(fm, `${name}: SKILL.md keeps its frontmatter first`);
|
|
116
|
+
const body = text.slice(fm[0].length).replace(/^\n+/, '');
|
|
117
|
+
assert.ok(body.startsWith(pre), `${name}: the preamble block is the first thing after the frontmatter and matches PREAMBLE.md byte for byte`);
|
|
118
|
+
assert.equal(text.split(policy.preamble.begin).length, 2, `${name}: the preamble appears exactly once`);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('every in-house skill names its dir, carries a description, and says what it was rebuilt from instead of carrying a sidecar', () => {
|
|
123
|
+
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
124
|
+
for (const name of ownDirs) {
|
|
125
|
+
const dir = path.join(SKILLS, name);
|
|
126
|
+
const text = read(path.join(dir, 'SKILL.md'));
|
|
127
|
+
const fm = frontmatter(text);
|
|
128
|
+
assert.equal(fm.name, name, `${name}: frontmatter names its own dir`);
|
|
129
|
+
assert.ok(fm.description && fm.description.length > 80, `${name}: a description the harness can route on`);
|
|
130
|
+
assert.ok(!fs.existsSync(path.join(dir, policy.sidecar)), `${name}: an in-house skill claims no upstream, so no ${policy.sidecar}`);
|
|
131
|
+
assert.ok(!fs.existsSync(path.join(dir, 'LICENSE')), `${name}: no upstream licence text travels with a rebuild`);
|
|
132
|
+
const afterPreamble = text.slice(text.indexOf(pre) + pre.length);
|
|
133
|
+
const section = afterPreamble.match(/^## Rebuilt from\n([\s\S]*?)(?=\n## )/m);
|
|
134
|
+
assert.ok(section, `${name}: a "## Rebuilt from" section is the first thing after the preamble`);
|
|
135
|
+
assert.match(afterPreamble.trimStart(), /^## Rebuilt from\n/, `${name}: nothing sits between the preamble and the Rebuilt-from section`);
|
|
136
|
+
assert.match(section[1], /builders#\/task\/\d+/, `${name}: the section links the spec task`);
|
|
137
|
+
assert.match(section[1], /ADR 0198/, `${name}: the section names the vendoring policy that made it a rebuild`);
|
|
138
|
+
assert.match(section[1], /REBUILD-SPEC/, `${name}: the section names the spec`);
|
|
139
|
+
assert.match(section[1], /no upstream bytes/i, `${name}: the section states no upstream bytes were consulted or copied`);
|
|
140
|
+
assert.match(section[1], /what changed in translation/i, `${name}: the section says where the rebuild departs from the documented behaviour`);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('every in-house skill works inside the world: the style library is the palette source, images are hero plates only, and no step mandates generating one', () => {
|
|
145
|
+
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
146
|
+
for (const name of ownDirs) {
|
|
147
|
+
const text = read(path.join(SKILLS, name, 'SKILL.md'));
|
|
148
|
+
const own = text.slice(text.indexOf(pre) + pre.length); // the skill's own rules, not the shared block
|
|
149
|
+
assert.ok(own.includes('modules/ui-design/styles/'), `${name}: names the style library as where a variant comes from`);
|
|
150
|
+
assert.match(own, /hero plates/i, `${name}: restates the owner's imagery rule in its own rules`);
|
|
151
|
+
assert.doesNotMatch(own, /\b(must|always|first|then)\s+generate\s+(an?\s+|the\s+)?(image|asset|photo|render)/i, `${name}: no step mandates image generation (ADR 0198's panel finding; the owner's rule)`);
|
|
152
|
+
assert.doesNotMatch(own, /\b(use|add|insert|prefer|fall back to|source)\s+(seeded\s+)?placeholder (photo|imag)/i, `${name}: no step reaches for seeded placeholder photography (naming the ban is fine; directing it is not)`);
|
|
153
|
+
assert.match(own, /Kill Switch|prefers-reduced-motion/, `${name}: its motion rules name the switch they live inside`);
|
|
154
|
+
assert.match(own, /kit\/render\.js/, `${name}: the kit's render is its pre-flight`);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test('the preamble copies are policy, not doc-entropy debt: the scanner skips the block and still flags a plain duplicate', () => {
|
|
159
|
+
const de = require(path.join(ROOT, 'scripts', 'gds', 'docs-entropy.js'));
|
|
160
|
+
const carriers = ['modules/ui-design/skills/PREAMBLE.md', ...ownDirs.map((n) => `modules/ui-design/skills/${n}/SKILL.md`)];
|
|
161
|
+
assert.ok(carriers.length >= 2, 'at least one own skill carries the block beside PREAMBLE.md');
|
|
162
|
+
for (const rel of carriers) assert.ok(read(path.join(ROOT, rel)).includes(policy.preamble.begin), `${rel} carries the block`);
|
|
163
|
+
const dupes = de.scanDuplicateProse(carriers);
|
|
164
|
+
assert.ok(!dupes.some((d) => d.snippet.startsWith(policy.preamble.begin)), 'the byte-identical preamble is not reported as duplicate prose');
|
|
165
|
+
// calibration: the same scanner over the same files still sees a plain paragraph twice
|
|
166
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ui-skills-dupe-'));
|
|
167
|
+
const para = 'A plain paragraph long enough to clear the scanner\'s 120-character floor, written twice so the duplicate-prose scan has something real to report.';
|
|
168
|
+
const a = path.join(tmp, 'a.md');
|
|
169
|
+
const b = path.join(tmp, 'b.md');
|
|
170
|
+
fs.writeFileSync(a, `# a\n\n${para}\n\n${read(path.join(SKILLS, 'PREAMBLE.md'))}`);
|
|
171
|
+
fs.writeFileSync(b, `# b\n\n${para}\n\n${read(path.join(SKILLS, 'PREAMBLE.md'))}`);
|
|
172
|
+
const rel = (p) => path.relative(ROOT, p).split(path.sep).join('/');
|
|
173
|
+
const control = de.scanDuplicateProse([rel(a), rel(b)]);
|
|
174
|
+
assert.equal(control.length, 1, 'the plain paragraph is flagged once');
|
|
175
|
+
assert.ok(control[0].snippet.startsWith('A plain paragraph'), 'and it is the plain paragraph, not the preamble');
|
|
176
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
177
|
+
});
|
|
178
|
+
|
|
96
179
|
// ── the manifest declares what is on disk, and nothing else ─────────────────
|
|
97
180
|
test('every skill the manifest contributes resolves to a skill dir (core .claude/skills or the module), and every module skill dir is declared', () => {
|
|
98
181
|
const declared = manifest.contributes.skills;
|
|
@@ -145,24 +228,31 @@ test('a module-owned skill lands in a materialised .claude/skills with its sidec
|
|
|
145
228
|
});
|
|
146
229
|
|
|
147
230
|
// ── the doors: /design lists them, the README rosters them, the ADR is indexed ──
|
|
148
|
-
test('/design lists every
|
|
231
|
+
test('/design lists every module skill (vendored or in-house) by name, one line each, and names the playwright plugin as a prerequisite', () => {
|
|
149
232
|
const design = read(path.join(ROOT, '.claude', 'skills', 'design', 'SKILL.md'));
|
|
150
|
-
for (const name of vendoredDirs) {
|
|
233
|
+
for (const name of [...vendoredDirs, ...ownDirs]) {
|
|
151
234
|
const line = design.split('\n').find((l) => l.includes(`\`/${name}\``) || l.includes(`**${name}**`));
|
|
152
235
|
assert.ok(line, `/design names ${name} on a line of its own`);
|
|
153
236
|
}
|
|
154
237
|
assert.match(design, /playwright/i, '/design names the playwright plugin');
|
|
155
238
|
});
|
|
156
239
|
|
|
157
|
-
test('the skills README
|
|
240
|
+
test('the skills README and the module CLAUDE.md roster every module skill by name', () => {
|
|
158
241
|
const readme = read(path.join(SKILLS, 'README.md'));
|
|
159
|
-
|
|
242
|
+
const claude = read(path.join(MODULE, 'CLAUDE.md'));
|
|
243
|
+
for (const name of [...vendoredDirs, ...ownDirs]) {
|
|
244
|
+
assert.ok(readme.includes(`\`${name}\``), `README rosters ${name}`);
|
|
245
|
+
assert.ok(claude.includes(`\`${name}\``), `modules/ui-design/CLAUDE.md names ${name}`);
|
|
246
|
+
}
|
|
160
247
|
assert.ok(readme.includes('policy.json') && readme.includes('PREAMBLE.md') && readme.includes('PROVENANCE.md'));
|
|
248
|
+
assert.ok(readme.includes('Rebuilt from'), 'the README says what a rebuild carries instead of a sidecar');
|
|
161
249
|
});
|
|
162
250
|
|
|
163
|
-
test('the vendoring
|
|
164
|
-
const adr = fs.readdirSync(path.join(ROOT, 'docs', 'adr')).find((f) => /^0198-/.test(f));
|
|
165
|
-
assert.ok(adr, 'docs/adr/0198-*.md exists');
|
|
251
|
+
test('the vendoring-policy ADR and the in-house-rebuild ADR exist and are indexed', () => {
|
|
166
252
|
const index = read(path.join(ROOT, 'docs', 'adr', 'README.md'));
|
|
167
|
-
|
|
253
|
+
for (const n of ['0198', '0220']) {
|
|
254
|
+
const adr = fs.readdirSync(path.join(ROOT, 'docs', 'adr')).find((f) => f.startsWith(`${n}-`));
|
|
255
|
+
assert.ok(adr, `docs/adr/${n}-*.md exists`);
|
|
256
|
+
assert.ok(index.includes(`](${adr})`), `docs/adr/README.md links ADR ${n}`);
|
|
257
|
+
}
|
|
168
258
|
});
|