@bongos/core 1.19.478 → 1.19.480
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 +100 -35
- package/.claude/skills/design/SKILL.md +9 -3
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -0
- package/clients/bongos-client/index.cjs +4 -0
- package/clients/bongos-client/index.d.ts +4 -0
- package/clients/bongos-client/index.mjs +4 -0
- package/docs/adr/0230-a-look-skill-is-a-composition-grammar-the-palette-is-the-pack.md +36 -0
- package/docs/adr/0231-the-style-session-an-owner-authors-a-look-inside-the-contract.md +32 -0
- package/docs/adr/README.md +2 -0
- package/docs/api/openapi.json +80 -1
- package/docs/api-reference.md +5 -3
- package/docs/copy-inventory.md +6 -6
- package/docs/copy-registry.json +6 -6
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +4 -0
- package/modules/economy/credits.js +78 -0
- package/modules/economy/module.json +1 -1
- package/modules/economy/reward.js +4 -0
- package/modules/economy/routes/credits.js +151 -0
- package/modules/hall-ui/public/md-reader.js +24 -1
- package/modules/ui-design/module.json +1 -1
- package/modules/ui-design/skills/README.md +14 -2
- package/modules/ui-design/skills/gpt-taste/SKILL.md +110 -0
- package/modules/ui-design/skills/industrial-brutalist-ui/SKILL.md +110 -0
- package/modules/ui-design/skills/minimalist-ui/SKILL.md +103 -0
- package/modules/ui-design/skills/stitch-design-taste/SKILL.md +91 -0
- package/modules/ui-design/skills/style/SKILL.md +112 -0
- package/modules/ui-design/styles/README.md +3 -0
- package/modules/ui-design/styles/blueprint/DESIGN.md +152 -0
- package/modules/ui-design/styles/blueprint/mock.html +308 -0
- package/modules/ui-design/styles/blueprint/mock.states.json +11 -0
- package/modules/ui-design/styles/blueprint/pack.json +33 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/module-api.js +1 -1
- package/tests/credit_ledger_read.mjs +347 -0
- package/tests/hall_reading_world.mjs +80 -0
- package/tests/own_scope_guard.mjs +24 -2
- package/tests/ui_design_skills.mjs +102 -11
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
// 0220) the same file pins the IN-HOUSE rebuilds under skills/<name>/: the same preamble
|
|
9
9
|
// first and once, a `## Rebuilt from` section instead of a sidecar (the spec task, ADR
|
|
10
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.
|
|
11
|
+
// mandate, and the preamble copies proven not to be doc-entropy debt. Since task 1003327
|
|
12
|
+
// (ADR 0230) it also pins the four LOOKS: each names the style-library entry it was tuned
|
|
13
|
+
// against, declares no colour of its own outside the legal black/white carve-out, adds no
|
|
14
|
+
// face, and keeps the translations that ADR fixed (the archetype that still ships both modes,
|
|
15
|
+
// the deterministic selection, the transcribed colour contract). Since task 1003475 (ADR
|
|
16
|
+
// 0231) a module skill declares one of TWO origins - a rebuild from a spec, or first party -
|
|
17
|
+
// and the origin pins branch on which; the /style session is the first original. DB-free.
|
|
12
18
|
import assert from 'node:assert/strict';
|
|
13
19
|
import { test } from 'node:test';
|
|
14
20
|
import { createRequire } from 'node:module';
|
|
@@ -200,6 +206,57 @@ test('the worked example of the image family is the grove specimen: the pair wit
|
|
|
200
206
|
assert.match(design, /grove-pod\.jpg/, 'the look\'s DESIGN.md names its specimen\'s plate instead of claiming it brings none');
|
|
201
207
|
});
|
|
202
208
|
|
|
209
|
+
// ── the four looks (task 1003327, ADR 0230): a composition grammar, never a palette ──
|
|
210
|
+
const LOOKS = ['minimalist-ui', 'industrial-brutalist-ui', 'gpt-taste', 'stitch-design-taste'];
|
|
211
|
+
const LIBRARY = ['chrome-world', 'expedition', 'grove'];
|
|
212
|
+
const ownRules = (name) => {
|
|
213
|
+
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
214
|
+
const text = read(path.join(SKILLS, name, 'SKILL.md'));
|
|
215
|
+
return text.slice(text.indexOf(pre) + pre.length);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
test('the four looks of task 1003327 exist as in-house skills, are declared, and each names the library entry it was tuned against', () => {
|
|
219
|
+
for (const name of LOOKS) {
|
|
220
|
+
assert.ok(ownDirs.includes(name), `${name}: skills/${name}/SKILL.md exists`);
|
|
221
|
+
assert.ok(manifest.contributes.skills.includes(name), `${name}: declared in contributes.skills`);
|
|
222
|
+
const own = ownRules(name);
|
|
223
|
+
assert.ok(LIBRARY.some((look) => own.includes(`\`${look}\``)), `${name}: names a style-library entry by directory, so a builder can render the grammar under a real look`);
|
|
224
|
+
assert.match(own, /1003327/, `${name}: names the port task`);
|
|
225
|
+
assert.match(own, /ADR 0230/, `${name}: names the look-skill ADR`);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('a look skill ships a grammar and no world of its own: no palette of its own, no face, the pack is the source', () => {
|
|
230
|
+
for (const name of LOOKS) {
|
|
231
|
+
const own = ownRules(name);
|
|
232
|
+
// the preamble's only legal literal is pure black or white; every other colour is a var() or a color-mix()
|
|
233
|
+
const illegal = (own.match(/#[0-9a-fA-F]{3,8}\b/g) || []).filter((h) => !/^#(0{3,8}|f{3,8})$/i.test(h));
|
|
234
|
+
assert.deepEqual(illegal, [], `${name}: a look skill declares no colour of its own (found ${illegal.join(', ')})`);
|
|
235
|
+
assert.doesNotMatch(own, /\b(add|load|install|import|declare|register)\s+(an?\s+|the\s+|a new\s+)?(@?font-face|webfont|typeface|font family|google font)/i, `${name}: a look skill adds no face; the pack's two stacks are the type system`);
|
|
236
|
+
assert.doesNotMatch(own, /https?:\/\/fonts\./i, `${name}: no font host of its own`);
|
|
237
|
+
assert.match(own, /the pack|instance's pack/i, `${name}: says the palette is the instance's pack`);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('each look keeps the translation ADR 0230 fixed: the substrate is an archetype, the selection is deterministic, the document transcribes, the placeholder photography is gone', () => {
|
|
242
|
+
const brutalist = ownRules('industrial-brutalist-ui');
|
|
243
|
+
assert.match(brutalist, /the other mode/i, 'brutalist: the substrate became an archetype and the other mode still ships');
|
|
244
|
+
assert.match(brutalist, /never mixed/i, 'brutalist: the two archetypes are never mixed in one interface');
|
|
245
|
+
const gpt = ownRules('gpt-taste');
|
|
246
|
+
assert.match(gpt, /deterministic, not random/i, 'gpt-taste: the selection is deterministic, not a roll');
|
|
247
|
+
assert.match(gpt, /sibling/i, 'gpt-taste: the selection is checked against sibling surfaces');
|
|
248
|
+
const stitch = ownRules('stitch-design-taste');
|
|
249
|
+
assert.match(stitch, /transcrib/i, 'stitch: the colour contract is transcribed from the pack');
|
|
250
|
+
assert.match(stitch, /diff/i, 'stitch: the thirteen are diffed against the pack, not retyped');
|
|
251
|
+
for (const name of ['minimalist-ui', 'gpt-taste']) {
|
|
252
|
+
assert.match(ownRules(name), /seeded placeholder photograph/i, `${name}: names the upstream's seeded placeholder photography, which this port drops`);
|
|
253
|
+
}
|
|
254
|
+
const index = read(path.join(ROOT, 'docs', 'adr', 'README.md'));
|
|
255
|
+
const adr = fs.readdirSync(path.join(ROOT, 'docs', 'adr')).find((f) => f.startsWith('0230-'));
|
|
256
|
+
assert.ok(adr, 'docs/adr/0230-*.md exists');
|
|
257
|
+
assert.ok(index.includes(`](${adr})`), 'docs/adr/README.md links ADR 0230');
|
|
258
|
+
});
|
|
259
|
+
|
|
203
260
|
test('every in-house SKILL.md opens with the PLATFORM PREAMBLE, byte-identical to PREAMBLE.md, exactly once, right after its frontmatter', () => {
|
|
204
261
|
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
205
262
|
for (const name of ownDirs) {
|
|
@@ -212,7 +269,7 @@ test('every in-house SKILL.md opens with the PLATFORM PREAMBLE, byte-identical t
|
|
|
212
269
|
}
|
|
213
270
|
});
|
|
214
271
|
|
|
215
|
-
test('every in-house skill names its dir, carries a description, and
|
|
272
|
+
test('every in-house skill names its dir, carries a description, and declares exactly one origin: a rebuild from a spec, or first party (ADR 0231)', () => {
|
|
216
273
|
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
217
274
|
for (const name of ownDirs) {
|
|
218
275
|
const dir = path.join(SKILLS, name);
|
|
@@ -221,17 +278,51 @@ test('every in-house skill names its dir, carries a description, and says what i
|
|
|
221
278
|
assert.equal(fm.name, name, `${name}: frontmatter names its own dir`);
|
|
222
279
|
assert.ok(fm.description && fm.description.length > 80, `${name}: a description the harness can route on`);
|
|
223
280
|
assert.ok(!fs.existsSync(path.join(dir, policy.sidecar)), `${name}: an in-house skill claims no upstream, so no ${policy.sidecar}`);
|
|
224
|
-
assert.ok(!fs.existsSync(path.join(dir, 'LICENSE')), `${name}: no upstream licence text travels with
|
|
281
|
+
assert.ok(!fs.existsSync(path.join(dir, 'LICENSE')), `${name}: no upstream licence text travels with an in-house skill`);
|
|
225
282
|
const afterPreamble = text.slice(text.indexOf(pre) + pre.length);
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
assert.
|
|
229
|
-
assert.match(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
283
|
+
const rebuilt = afterPreamble.match(/^## Rebuilt from\n([\s\S]*?)(?=\n## )/m);
|
|
284
|
+
const original = afterPreamble.match(/^## First party\n([\s\S]*?)(?=\n## )/m);
|
|
285
|
+
assert.ok(!!rebuilt !== !!original, `${name}: exactly one origin section - a rebuild carries "## Rebuilt from", an original carries "## First party"`);
|
|
286
|
+
assert.match(afterPreamble.trimStart(), /^## (Rebuilt from|First party)\n/, `${name}: the origin section is the first thing after the preamble, with nothing between`);
|
|
287
|
+
if (rebuilt) {
|
|
288
|
+
assert.match(rebuilt[1], /builders#\/task\/\d+/, `${name}: the section links the spec task`);
|
|
289
|
+
assert.match(rebuilt[1], /ADR 0198/, `${name}: the section names the vendoring policy that made it a rebuild`);
|
|
290
|
+
assert.match(rebuilt[1], /REBUILD-SPEC/, `${name}: the section names the spec`);
|
|
291
|
+
assert.match(rebuilt[1], /no upstream bytes/i, `${name}: the section states no upstream bytes were consulted or copied`);
|
|
292
|
+
assert.match(rebuilt[1], /what changed in translation/i, `${name}: the section says where the rebuild departs from the documented behaviour`);
|
|
293
|
+
} else {
|
|
294
|
+
assert.match(original[1], /builders#\/task\/\d+/, `${name}: the section links the task that authored it`);
|
|
295
|
+
assert.match(original[1], /no upstream/i, `${name}: an original states plainly that it has no upstream`);
|
|
296
|
+
assert.match(original[1], /ADR 0231/, `${name}: the section names the two-origin rule`);
|
|
297
|
+
assert.match(original[1], /why it exists/i, `${name}: an original says why it exists, since it has no spec to point at`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// ── the /style session (task 1003475, ADR 0231): the module's first original skill ──
|
|
303
|
+
test('the /style session is a first-party skill that runs four bounded steps and never writes the instance\'s world', () => {
|
|
304
|
+
const pre = read(path.join(SKILLS, 'PREAMBLE.md')).trimEnd();
|
|
305
|
+
assert.ok(ownDirs.includes('style'), 'skills/style/SKILL.md exists');
|
|
306
|
+
assert.ok(manifest.contributes.skills.includes('style'), 'declared in contributes.skills');
|
|
307
|
+
const text = read(path.join(SKILLS, 'style', 'SKILL.md'));
|
|
308
|
+
const own = text.slice(text.indexOf(pre) + pre.length);
|
|
309
|
+
assert.match(own, /^## First party\n/m, 'it declares itself first party, not a rebuild');
|
|
310
|
+
for (const step of ['Search', 'Create', 'Prove', 'Adopt']) {
|
|
311
|
+
assert.ok(new RegExp(`## Step \\d+ . ${step}`, 'i').test(own), `the session carries the ${step} step`);
|
|
234
312
|
}
|
|
313
|
+
for (const cli of ['kit/contrast.js', 'kit/render.js', 'kit/check-mock.js', 'tests/ui_design_styles.mjs']) {
|
|
314
|
+
assert.ok(own.includes(cli), `the PROVE step names ${cli}`);
|
|
315
|
+
}
|
|
316
|
+
assert.match(own, /sixteenth token/i, 'a look that needs a sixteenth token is refused at the door');
|
|
317
|
+
assert.match(own, /never a fork of a sheet|not a fork of a sheet/i, 'a look is a pack, never a fork of a sheet');
|
|
318
|
+
assert.match(own, /does not edit `config\/branding\.json`|read, never written/i, 'adopting a look stays the owner\'s decision; the session never writes the host boundary');
|
|
319
|
+
assert.doesNotMatch(own, /bypassPermissions|--dangerously-skip-permissions/, 'no permission bypass');
|
|
320
|
+
assert.doesNotMatch(own, /\b(write|add|install|register)\b[^.\n]{0,60}\b(PostToolUse|PreToolUse|Stop)\b[^.\n]{0,40}\bhooks?\b/i, 'no step writes a hook into a harness config');
|
|
321
|
+
assert.doesNotMatch(own, /\b(curl|wget|fetch|download)\b[^.\n]{0,60}\bhttps?:\/\//i, 'no remote bundle download');
|
|
322
|
+
const index = read(path.join(ROOT, 'docs', 'adr', 'README.md'));
|
|
323
|
+
const adr = fs.readdirSync(path.join(ROOT, 'docs', 'adr')).find((f) => f.startsWith('0231-'));
|
|
324
|
+
assert.ok(adr, 'docs/adr/0231-*.md exists');
|
|
325
|
+
assert.ok(index.includes(`](${adr})`), 'docs/adr/README.md links ADR 0231');
|
|
235
326
|
});
|
|
236
327
|
|
|
237
328
|
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', () => {
|