@bongos/core 1.20.39 → 1.20.41
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 +260 -240
- package/.claude/skills/design/SKILL.md +6 -5
- package/docs/adr/0081-tool-agnostic-design-layer.md +1 -1
- package/docs/adr/0198-third-party-skill-vendoring-policy.md +2 -2
- package/docs/adr/0349-a-version-preview-is-a-sandboxed-child-the-web-tier-launches.md +1 -0
- package/docs/file-map.md +51 -54
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +7 -5
- package/docs/onboarding/slash-commands.md +1 -1
- package/modules/design-styles/CLAUDE.md +15 -0
- package/modules/design-styles/module.json +12 -0
- package/modules/{ui-design → design-styles}/skills/PREAMBLE.md +2 -2
- package/modules/{ui-design → design-styles}/skills/README.md +6 -6
- package/modules/{ui-design → design-styles}/skills/brandkit/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/design-taste-frontend/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/gpt-taste/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/high-end-visual-design/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/image-to-code/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/imagegen-frontend-mobile/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/imagegen-frontend-web/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/impeccable/SKILL.md +3 -3
- package/modules/{ui-design → design-styles}/skills/industrial-brutalist-ui/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/minimalist-ui/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/policy.json +1 -1
- package/modules/{ui-design → design-styles}/skills/redesign-existing-projects/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/stitch-design-taste/SKILL.md +2 -2
- package/modules/{ui-design → design-styles}/skills/style/SKILL.md +2 -2
- package/modules/npm-release/preview/divert.js +16 -6
- package/modules/npm-release/preview/proxy.js +4 -1
- package/modules/npm-release/routes/preview.js +6 -5
- package/modules/pixel-art/CLAUDE.md +15 -0
- package/modules/pixel-art/module.json +12 -0
- package/modules/provisioning/starter-bundles.js +15 -0
- package/modules/ui-design/kit/serve.js +2 -0
- package/modules/ui-design/module.json +3 -3
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/gds/doc-cli-guard.js +1 -1
- package/scripts/gds/fitness-ratchets.js +4 -1
- package/scripts/gds/fitness.js +2 -1
- package/scripts/gds/publish-manifest.js +2 -0
- package/scripts/gds/skill-lint.js +30 -8
- package/src/bongos/module-scope-map.js +8 -2
- package/src/module-api.js +1 -1
- package/tests/claude_materialize.mjs +9 -8
- package/tests/module_loader.mjs +1 -1
- package/tests/npm_release_preview_divert.mjs +10 -0
- package/tests/npm_release_preview_proxy.mjs +26 -0
- package/tests/npm_release_preview_routes.mjs +15 -2
- package/tests/opt_in_skill_modules.mjs +165 -0
- package/tests/skill_lint.mjs +26 -2
- package/tests/ui_design_skills.mjs +29 -17
- package/modules/ui-design/skills/design-taste-frontend-v1/SKILL.md +0 -135
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/adapt.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/animate.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/audit.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/bolder.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/clarify.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/colorize.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/critique.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/distill.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/document.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/extract.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/harden.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/layout.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/onboard.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/optimize.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/polish.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/quieter.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/shape.md +0 -0
- /package/modules/{ui-design → design-styles}/skills/impeccable/reference/typeset.md +0 -0
- /package/{.claude → modules/pixel-art}/skills/otb-character-review/SKILL.md +0 -0
- /package/{.claude → modules/pixel-art}/skills/otb-design-review/SKILL.md +0 -0
- /package/{.claude → modules/pixel-art}/skills/otb-feedback-capture/SKILL.md +0 -0
- /package/{.claude → modules/pixel-art}/skills/otb-figma-sync/SKILL.md +0 -0
- /package/{.claude → modules/pixel-art}/skills/otb-tile-generate/SKILL.md +0 -0
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Paid: each image is made on the project's image key. It adds the picture files to the project.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Paid: each image is made on the project's image key. It adds the picture files to the project.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Uses your session. A review changes nothing; a fix changes the page.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -65,7 +65,7 @@ The full list, grouped:
|
|
|
65
65
|
|
|
66
66
|
The setup step is the preamble's world load, done **once per session** and not repeated: the pack, the tokens, the root `DESIGN.md`, and `docs/project-context.template.md` for product truth. The directives that come back are the world's own named rules and its Do's and Don'ts; quote them from the files, never from memory. Then, before editing anything, inspect the target **and at least one source of existing visual truth** for it: the sheet the page loads, a sibling component, the page's states file, or a plate under the instance's assets. A surface is edited only after both have been read.
|
|
67
67
|
|
|
68
|
-
This skill lives at `modules/
|
|
68
|
+
This skill lives at `modules/design-styles/skills/impeccable/` in the core and at `.claude/skills/impeccable/` once materialised into an instance; the playbooks are always `reference/<name>.md` relative to this file. If a harness has put the file somewhere else, resolve the playbooks relative to wherever this file was read from, and fall back to the module path.
|
|
69
69
|
|
|
70
70
|
## The three homes, and what they are here
|
|
71
71
|
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Uses your session. It changes the page, and you check it on a preview.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Uses your session. It changes the page, and you check it on a preview.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_doc": "The vendoring policy for third-party UI skills in the
|
|
2
|
+
"_doc": "The vendoring policy for third-party UI skills in the design-styles module (task 1003321, ADR 0198; moved out of ui-design by task 1004470). tests/ui_design_skills.mjs enforces it; modules/design-styles/skills/README.md explains it. A skill lands under skills/vendor/<name>/ only with a PROVENANCE.md sidecar, a licence on the allowlist, a /scan-before-install verdict that is not dangerous, and the PLATFORM PREAMBLE block (PREAMBLE.md, byte-identical) at the top of its SKILL.md body. A dangerous verdict or a licence off the allowlist lands a rebuild spec, never a copy.",
|
|
3
3
|
"licenceAllowlist": ["Apache-2.0", "MIT", "BSD-2-Clause", "BSD-3-Clause", "CC-BY-4.0"],
|
|
4
4
|
"verdictsThatMayLand": ["clean", "caution"],
|
|
5
5
|
"sidecar": "PROVENANCE.md",
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Uses your session. It changes the existing pages, and you check them on a preview.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Uses your session. It writes one brief document and changes no pages.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -13,8 +13,8 @@ cost: >-
|
|
|
13
13
|
Uses your session. The new look is only used once you choose to adopt it.
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
-
<!-- BEGIN PLATFORM PREAMBLE ·
|
|
17
|
-
> **Platform preamble — read before any rule below.** This skill ships with the `
|
|
16
|
+
<!-- BEGIN PLATFORM PREAMBLE · design-styles 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/design-styles/skills/PREAMBLE.md and tests/ui_design_skills.mjs fails on drift -->
|
|
17
|
+
> **Platform preamble — read before any rule below.** This skill ships with the `design-styles` module (vendored from a scanned origin, or rebuilt in-house from a spec) and runs INSIDE an instance's world, which it reads first and never overrides.
|
|
18
18
|
>
|
|
19
19
|
> 1. **Load the world before any taste rule.** `config/branding.json` over `config/branding.neutral.json` (`theme.ui` is the fifteen tokens: <redacted> colours and two font stacks), `config/design-tokens.json` over `config/design-tokens.neutral.json`, and `DESIGN.md` at the repo root: the instance's palette and derived tiers, faces, materials, motion grammar, components, and its Do's and Don'ts. Where an instance has no `DESIGN.md`, the neutral pack is the world and the platform floors in item 6 are the whole rulebook; say so and build to them. Never invent a palette.
|
|
20
20
|
> 2. **The fifteen-token contract is the only colour source.** Every colour is a `var()` or a `color-mix()` of the fifteen; the only legal literal is pure black or white with alpha as a scrim, mask or halo. No page `:root` (page tokens live on `body`), and every dark rule is written twice: `:root[data-mode="dark"]` and its `prefers-color-scheme` twin.
|
|
@@ -44,9 +44,19 @@ function pathOf(req) {
|
|
|
44
44
|
return q === -1 ? url : url.slice(0, q);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
/**
|
|
48
|
-
function
|
|
49
|
-
return
|
|
47
|
+
/** Path/HttpOnly/SameSite/Secure the steering cookie is set with; the clear repeats them. */
|
|
48
|
+
function steerFlags(req) {
|
|
49
|
+
return `HttpOnly; SameSite=Lax${req && req.secure ? '; Secure' : ''}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** The Set-Cookie value that sets the steering cookie. */
|
|
53
|
+
function setCookie(version, req) {
|
|
54
|
+
return `${COOKIE_NAME}=${version}; Path=/; ${steerFlags(req)}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The Set-Cookie value that removes it: same Path, SameSite and Secure as the set (task 1004466). */
|
|
58
|
+
function clearCookie(req) {
|
|
59
|
+
return `${COOKIE_NAME}=; Path=/; Max-Age=0; ${steerFlags(req)}`;
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
// Run an express-style gate to its verdict without letting it write a response of its own:
|
|
@@ -77,14 +87,14 @@ function createDivert({ supervisor, forward, requireBuilder, requirePermission }
|
|
|
77
87
|
const st = supervisor.status();
|
|
78
88
|
if (st.state !== 'running' || st.version !== wanted) {
|
|
79
89
|
// The preview this cookie pointed at is gone: drop the cookie and serve the live hall.
|
|
80
|
-
res.append('Set-Cookie', clearCookie());
|
|
90
|
+
res.append('Set-Cookie', clearCookie(req));
|
|
81
91
|
return next();
|
|
82
92
|
}
|
|
83
93
|
const p = pathOf(req);
|
|
84
94
|
if (AUTH_PATH.test(p) || PREVIEW_PATH.test(p)) return next();
|
|
85
95
|
if (req.headers.authorization) return next();
|
|
86
96
|
if (!(await passes(requireBuilder, req)) || !(await passes(mayPreview, req))) {
|
|
87
|
-
res.append('Set-Cookie', clearCookie());
|
|
97
|
+
res.append('Set-Cookie', clearCookie(req));
|
|
88
98
|
return next();
|
|
89
99
|
}
|
|
90
100
|
supervisor.touch();
|
|
@@ -92,4 +102,4 @@ function createDivert({ supervisor, forward, requireBuilder, requirePermission }
|
|
|
92
102
|
};
|
|
93
103
|
}
|
|
94
104
|
|
|
95
|
-
module.exports = { createDivert, cookieVersion, clearCookie, AUTH_PATH, PREVIEW_PATH };
|
|
105
|
+
module.exports = { createDivert, cookieVersion, clearCookie, setCookie, AUTH_PATH, PREVIEW_PATH };
|
|
@@ -74,7 +74,10 @@ function createProxy({ port, banner, exitHref, httpImpl = http } = {}) {
|
|
|
74
74
|
{ host: '127.0.0.1', port: port(), method: req.method, path: req.originalUrl || req.url, headers },
|
|
75
75
|
(upRes) => {
|
|
76
76
|
const out = {};
|
|
77
|
-
|
|
77
|
+
// SET-COOKIE NEVER CROSSES (task 1004466). The preview shares the live hall's origin,
|
|
78
|
+
// so a cookie it set would overwrite the live hall's own (cb_stealth, the session,
|
|
79
|
+
// the steering cookie) and lock its owner out. Its cookies stay with the child.
|
|
80
|
+
for (const [k, v] of Object.entries(upRes.headers)) if (!HOP.has(k) && k.toLowerCase() !== 'set-cookie') out[k] = v;
|
|
78
81
|
const isPage = /^text\/html\b/i.test(String(upRes.headers['content-type'] || ''));
|
|
79
82
|
if (!isPage) {
|
|
80
83
|
res.writeHead(upRes.statusCode, out);
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
|
|
21
21
|
const express = require('express');
|
|
22
22
|
const api = require('../../../src/module-api');
|
|
23
|
-
const { createDivert, clearCookie } = require('../preview/divert');
|
|
24
|
-
const { createProxy
|
|
23
|
+
const { createDivert, clearCookie, setCookie } = require('../preview/divert');
|
|
24
|
+
const { createProxy } = require('../preview/proxy');
|
|
25
25
|
const { previewable } = require('../preview/supervisor');
|
|
26
26
|
const { VERSION_RE, PACKAGE } = require('../preview/commands');
|
|
27
27
|
|
|
@@ -119,14 +119,15 @@ module.exports = function buildNpmReleasePreviewRouter({
|
|
|
119
119
|
if (!VERSION_RE.test(v) || st.state !== 'running' || st.version !== v) {
|
|
120
120
|
return failure(res, 409, 'preview_not_running', 'That preview is not running.');
|
|
121
121
|
}
|
|
122
|
-
|
|
123
|
-
res.
|
|
122
|
+
res.append('Set-Cookie', setCookie(v, req));
|
|
123
|
+
res.set('Cache-Control', 'no-store');
|
|
124
124
|
sup.touch();
|
|
125
125
|
return res.redirect(302, '/');
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
router.get('/npm-release/preview/exit', api.requireBuilder, mayPreview, (req, res) => {
|
|
129
|
-
res.append('Set-Cookie', clearCookie());
|
|
129
|
+
res.append('Set-Cookie', clearCookie(req));
|
|
130
|
+
res.set('Cache-Control', 'no-store');
|
|
130
131
|
res.redirect(302, '/deploy');
|
|
131
132
|
});
|
|
132
133
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @bongos/core — installed platform dependency (not your project's CLAUDE.md)
|
|
2
|
+
|
|
3
|
+
This file is a placeholder shipped inside the **@bongos/core** package. The core's own
|
|
4
|
+
internal agent notes are intentionally omitted from the published artifact so they cannot
|
|
5
|
+
load into your instance's context.
|
|
6
|
+
|
|
7
|
+
**It does not govern this repository.** Your own root `CLAUDE.md`, your `.claude/`
|
|
8
|
+
directory, and the live Bongos database are the source of truth for how work happens here
|
|
9
|
+
and who may do what.
|
|
10
|
+
|
|
11
|
+
You are seeing this only because an agent opened a file under `node_modules/@bongos/core/`.
|
|
12
|
+
Nothing in here needs to be read to use the platform — run `bongos help` for commands.
|
|
13
|
+
|
|
14
|
+
_To work ON the platform core itself, use the standalone @bongos/core source repository,
|
|
15
|
+
not this vendored copy._
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"key": "pixel-art",
|
|
3
|
+
"title": "Pixel-art skills (tile generation, tile and animation review, feedback capture, the Figma tile canvas)",
|
|
4
|
+
"description": "The five pixel-art SKILLS an instance with a pixel-art world turns on: otb-tile-generate, otb-design-review, otb-character-review, otb-feedback-capture and otb-figma-sync (task 1004470, owner ruling on blocker 1000139). They were orphans in the core's .claude/skills/: docs attributed them to art-pipeline / character-anim, neither of which has a module.json (ADR 0272), and modules/art-pipeline/ never publishes because it carries copyrighted reference maps (ADR 0098). This module carries ONLY the skill text, never a reference map, a palette, a rubric or the generation pipeline — those stay with the instance's own art-pipeline host module, which the skills read at their documented paths. default: false because most instances have no pixel-art world, and every skill description is resident in every session whether it is used or not. Declaration-only: no routes, no migrations, no port, so turning it off withdraws only these skills.",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"coreVersion": "^1.19.0",
|
|
7
|
+
"default": false,
|
|
8
|
+
"maintenance": { "status": "core-maintained" },
|
|
9
|
+
"contributes": { "skills": ["otb-tile-generate", "otb-design-review", "otb-character-review", "otb-feedback-capture", "otb-figma-sync"] },
|
|
10
|
+
"provides": [],
|
|
11
|
+
"consumes": []
|
|
12
|
+
}
|
|
@@ -124,6 +124,21 @@ const OPTIONAL_MODULES = Object.freeze([
|
|
|
124
124
|
summary: 'A Discord server that carries your build news, and lets people send ideas and bug reports back.',
|
|
125
125
|
aliases: Object.freeze(['chatroom', 'talk', 'messaging', 'community', 'announcements', 'notifications']),
|
|
126
126
|
}),
|
|
127
|
+
// The two opt-in SKILL modules of task 1004470: no routes and no page, only extra
|
|
128
|
+
// commands for the AI. Off by default because every command's description costs
|
|
129
|
+
// context in every session, used or not.
|
|
130
|
+
Object.freeze({
|
|
131
|
+
key: 'design-styles',
|
|
132
|
+
label: 'Design styles',
|
|
133
|
+
summary: 'Extra ways for the AI to style your pages: ready-made looks, a polish pass, and a way to author your own look.',
|
|
134
|
+
aliases: Object.freeze(['theme', 'branding', 'visual', 'taste', 'aesthetic', 'layout']),
|
|
135
|
+
}),
|
|
136
|
+
Object.freeze({
|
|
137
|
+
key: 'pixel-art',
|
|
138
|
+
label: 'Pixel-art tools',
|
|
139
|
+
summary: 'Commands to generate game tiles and sprites, score them against your art rules, and keep a style guide.',
|
|
140
|
+
aliases: Object.freeze(['tileset', 'graphics', 'artwork', 'retro', 'drawing', 'gamedev']),
|
|
141
|
+
}),
|
|
127
142
|
]);
|
|
128
143
|
|
|
129
144
|
// The opt-in keys alone, for the membership tests the normalizer runs. Derived,
|
|
@@ -130,6 +130,8 @@ const STARTER_BUNDLES_FIXTURE = {
|
|
|
130
130
|
optional: [
|
|
131
131
|
{ key: 'agents', label: 'Extra agents', summary: 'More AI agents alongside the ones every project gets, for reading, research and review.', aliases: ['bots', 'assistants', 'automation', 'llm', 'helpers'] },
|
|
132
132
|
{ key: 'discord', label: 'Discord', summary: 'A Discord server that carries your build news, and lets people send ideas and bug reports back.', aliases: ['chatroom', 'talk', 'messaging', 'community', 'announcements', 'notifications'] },
|
|
133
|
+
{ key: 'design-styles', label: 'Design styles', summary: 'Extra ways for the AI to style your pages: ready-made looks, a polish pass, and a way to author your own look.', aliases: ['theme', 'branding', 'visual', 'taste', 'aesthetic', 'layout'] },
|
|
134
|
+
{ key: 'pixel-art', label: 'Pixel-art tools', summary: 'Commands to generate game tiles and sprites, score them against your art rules, and keep a style guide.', aliases: ['tileset', 'graphics', 'artwork', 'retro', 'drawing', 'gamedev'] },
|
|
133
135
|
],
|
|
134
136
|
};
|
|
135
137
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"key": "ui-design",
|
|
3
|
-
"title": "UI design (the design contract, its adapters and sync, the /design playbook, the kit, the
|
|
4
|
-
"description": "The platform capability that lets any builder on any instance create and design good-looking, functional UIs in line with that instance's world (scoped with the owner 2026-08-28; task 1003324, ADR 0197). It ships METHOD and never a world: the neutral design contract of ADR 0081 with its tool adapters (Claude Design, Figma), their sync CLIs and the validator; the /design playbook for ui-discipline work;
|
|
3
|
+
"title": "UI design (the design contract, its adapters and sync, the /design playbook, the kit, the styles)",
|
|
4
|
+
"description": "The platform capability that lets any builder on any instance create and design good-looking, functional UIs in line with that instance's world (scoped with the owner 2026-08-28; task 1003324, ADR 0197). It ships METHOD and never a world: the neutral design contract of ADR 0081 with its tool adapters (Claude Design, Figma), their sync CLIs and the validator; the /design playbook for ui-discipline work; the look-before-you-ship kit (kit/) and the style library (styles/). The thirteen design-style skills that lived in skills/ are the opt-in design-styles module since task 1004470; /design reaches them when that module is on. The instance's world — its branding pack, config/design-tokens.*, config/design-sources.json and its DESIGN.md — stays in config/ and at the repo root as the host boundary this module reads and never owns (ADR 0062 §7). Cloud Bongos's own front door is this module's first customer, not its owner. default-on because every instance has a face. No routes, no migrations, no port: declaration-only like character-anim, so disabling it withdraws only the skills it contributes and touches no served surface.",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"coreVersion": "^1.19.0",
|
|
7
7
|
"default": true,
|
|
8
8
|
"maintenance": { "status": "core-maintained" },
|
|
9
|
-
"contributes": { "skills": ["design", "design-sync", "figma-design-sync"
|
|
9
|
+
"contributes": { "skills": ["design", "design-sync", "figma-design-sync"], "disciplines": ["ui"] },
|
|
10
10
|
"declarativeSeams": { "skills": ["design", "design-sync", "figma-design-sync"] },
|
|
11
11
|
"provides": [],
|
|
12
12
|
"consumes": []
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.41",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.20.
|
|
9
|
+
"version": "1.20.41",
|
|
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.20.
|
|
3
|
+
"version": "1.20.41",
|
|
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/release-notes.json
CHANGED
|
@@ -8343,5 +8343,17 @@
|
|
|
8343
8343
|
"id": "1004464",
|
|
8344
8344
|
"text": "Setting up an app on Render from the project wizard no longer fails when the owner leaves the build command empty. The box now comes filled in with Render's usual build command for the chosen language, which the owner can chan"
|
|
8345
8345
|
}
|
|
8346
|
+
],
|
|
8347
|
+
"1.20.40": [
|
|
8348
|
+
{
|
|
8349
|
+
"id": "1004466",
|
|
8350
|
+
"text": "Stop the version preview from overwriting the live hall's cookies, and make leaving a preview reliably clear it."
|
|
8351
|
+
}
|
|
8352
|
+
],
|
|
8353
|
+
"1.20.41": [
|
|
8354
|
+
{
|
|
8355
|
+
"id": "1004470",
|
|
8356
|
+
"text": "Projects that don't do pixel art or design styling no longer carry 18 unused AI commands in every session (about a third less to load); projects that want them turn them on with one setting."
|
|
8357
|
+
}
|
|
8346
8358
|
]
|
|
8347
8359
|
}
|
|
@@ -39,7 +39,7 @@ const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
|
39
39
|
const DOC_CLI_ALLOW = new Map([
|
|
40
40
|
['.claude/skills/paint/SKILL.md::scripts/gds/art-stage.js',
|
|
41
41
|
'art-stage.js ships with the art-pipeline HOST module, which publish-manifest.js excludes from core — absent from a core-only checkout by design; the skill says so inline.'],
|
|
42
|
-
['
|
|
42
|
+
['modules/pixel-art/skills/otb-tile-generate/SKILL.md::scripts/gds/art-stage.js',
|
|
43
43
|
'same as paint/SKILL.md — the art staging CLI travels with the excluded art-pipeline module, not the portable core.'],
|
|
44
44
|
['docs/session-logs/2026-09-10-task-1003507-the-box-that-could-not-be-reaped.md::scripts/gds/box.js',
|
|
45
45
|
'a dated session log — the historical record, never rewritten — of work on a CLI the dev-box removal deleted (task 1003893); it describes what was run then, not what to run now.'],
|
|
@@ -421,7 +421,10 @@ function apiAliasCallerMetrics() {
|
|
|
421
421
|
function skillListingMetrics() {
|
|
422
422
|
try {
|
|
423
423
|
const lint = require('./skill-lint.js');
|
|
424
|
-
|
|
424
|
+
// Resident skills only (task 1004470): a skill owned by a module this checkout leaves
|
|
425
|
+
// off (pixel-art, design-styles — both default: false) is in no session's listing here.
|
|
426
|
+
const files = lint.listSkillFiles();
|
|
427
|
+
return { skill_listing_chars: lint.lintSkills(files, { resident: lint.residentSkillFiles(undefined, { files }) }).listingChars };
|
|
425
428
|
} catch (e) {
|
|
426
429
|
// Fail open, but never SILENTLY: an unenforced ratchet that says nothing is
|
|
427
430
|
// indistinguishable from a passing one, which is how a budget stops being a
|
package/scripts/gds/fitness.js
CHANGED
|
@@ -1198,7 +1198,8 @@ function checkSkillFrontmatter() {
|
|
|
1198
1198
|
return { name: 'skill frontmatter parses (task 1003548)', ok: true, hardFail: false, violations, warnings: [`skill-lint unavailable: ${e.message}`], note: 'linter missing — check skipped.' };
|
|
1199
1199
|
}
|
|
1200
1200
|
const files = lint.listSkillFiles(INSTANCE_ROOT);
|
|
1201
|
-
|
|
1201
|
+
// Lint every file; count the listing over the skills RESIDENT here (task 1004470).
|
|
1202
|
+
const report = lint.lintSkills(files, { resident: lint.residentSkillFiles(INSTANCE_ROOT, { files }) });
|
|
1202
1203
|
const rel = (f) => path.relative(INSTANCE_ROOT, f).replace(/\\/g, '/');
|
|
1203
1204
|
const long = [];
|
|
1204
1205
|
for (const r of report.results) {
|
|
@@ -65,6 +65,8 @@ const PUBLISH_ALLOWLIST = [
|
|
|
65
65
|
'modules/specialities/', // role sub-specialities (task 1003855, ADR 0296). default:true, so it MUST be here, and the copy-desk asymmetry above applies verbatim: the settings panel ships regardless because modules/hall-ui/ is allowlisted as one subtree, so omitting this line would put a "Your specialities" section in every instance's settings page whose every call 404s.
|
|
66
66
|
'modules/copy-desk/', // the artist's loop over user-facing TEXT (goal 1000074, ADR 0178). default:true, so it MUST be here — and note the ASYMMETRY that makes omitting it worse than useless: its hall surface ships regardless, because modules/hall-ui/ is allowlisted as one subtree. A released core carrying the page and the nav entry but not the routes behind them puts a tab in every instance's hall whose every call 404s. The module and its page are only ever added or removed together; tests/publish_manifest.mjs holds that pair.
|
|
67
67
|
'modules/ui-design/', // the design contract + its adapters/CLIs + the /design playbook (task 1003324, ADR 0197). default:true, so it MUST be here: a released core without it would materialize skills (design, design-sync, figma-design-sync) whose CLIs and adapters do not exist.
|
|
68
|
+
'modules/design-styles/', // the thirteen opt-in design-style skills split out of ui-design (task 1004470). default:false, but MUST be here: shipped is not enabled, and a released core without it hands an instance that turns it on an "unknown module" with nothing to materialize. Skill text only.
|
|
69
|
+
'modules/pixel-art/', // the five opt-in pixel-art skills (task 1004470), which shipped from .claude/skills/ before this. default:false. SKILL.md text only — never a reference map, a palette or generated art: those are modules/art-pipeline/, which CONTENT_EXCLUDE keeps out below for the copyright reason (ADR 0098).
|
|
68
70
|
'modules/hall-ui/',
|
|
69
71
|
'modules/status-ui/',
|
|
70
72
|
'modules/public-landing/', // the front door (task 1003322, ADR 0218) — the repo-root public-landing/ entry this replaces was always here, and for the same reason: default:true, and it is the only thing an instance serves at its apex root. Omit it and a released core answers the game-less 404 tail on its own home page.
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
// Usage:
|
|
26
26
|
// node scripts/gds/skill-lint.js lint every skill Claude Code can load — .claude/skills/*
|
|
27
27
|
// plus the module-owned modules/*/skills/* that materialize
|
|
28
|
-
// into it; exit 1 on any error
|
|
28
|
+
// into it; exit 1 on any error. The listing total counts
|
|
29
|
+
// only the skills RESIDENT here: a skill owned by a module
|
|
30
|
+
// this checkout's config leaves off is linted, not counted
|
|
31
|
+
// (task 1004470)
|
|
29
32
|
// node scripts/gds/skill-lint.js <file...> lint specific files
|
|
30
33
|
// node scripts/gds/skill-lint.js --hook PostToolUse mode: read the hook JSON on stdin, lint the
|
|
31
34
|
// edited file if it is a SKILL.md, print findings, exit 0
|
|
@@ -146,11 +149,28 @@ function listSkillFiles(root = REPO_ROOT) {
|
|
|
146
149
|
return [...core, ...owned];
|
|
147
150
|
}
|
|
148
151
|
|
|
149
|
-
//
|
|
150
|
-
|
|
152
|
+
// The subset of listSkillFiles() that is actually RESIDENT for an instance — what
|
|
153
|
+
// claude-materialize.js would land in its .claude/skills/ (task 1004470). Linting still
|
|
154
|
+
// covers every file (a defect in an opt-in module's skill must not wait for the module
|
|
155
|
+
// to be switched on), but the listing cost is a per-session number, and a skill owned by
|
|
156
|
+
// a module the instance leaves off is never in that session's listing. Enablement is the
|
|
157
|
+
// materialiser's own rule (moduleSkillRoster: the instance's config/modules.json, else the
|
|
158
|
+
// module's `default`), read from there rather than restated. Fails open to the full list
|
|
159
|
+
// if the materialiser cannot load, so the number can only ever over-report.
|
|
160
|
+
function residentSkillFiles(root = REPO_ROOT, { instanceDir = root, files = listSkillFiles(root) } = {}) {
|
|
161
|
+
let off;
|
|
162
|
+
try { off = require('./claude-materialize.js').disabledModuleSkills({ coreRoot: root, instanceDir }); } catch (_) { return files; }
|
|
163
|
+
return files.filter((f) => !off.has(path.basename(path.dirname(f))));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Lint a set of files; returns per-file results plus the listing total vs budget. The
|
|
167
|
+
// listing counts `resident` (a list of paths) when given, else every linted file.
|
|
168
|
+
function lintSkills(files, { resident } = {}) {
|
|
151
169
|
const results = files.map((f) => lintSkillFile(fs.readFileSync(f, 'utf8'), { file: f }));
|
|
152
|
-
const
|
|
153
|
-
|
|
170
|
+
const counted = resident ? new Set(resident.map((f) => path.resolve(f))) : null;
|
|
171
|
+
const listed = counted ? results.filter((r) => counted.has(path.resolve(r.file))) : results;
|
|
172
|
+
const listingChars = listed.reduce((a, r) => a + r.listingChars, 0);
|
|
173
|
+
return { results, listingChars, listedSkills: listed.length, budgetChars: LISTING_BUDGET_CHARS, overBudget: listingChars > LISTING_BUDGET_CHARS };
|
|
154
174
|
}
|
|
155
175
|
|
|
156
176
|
// The PostToolUse hook's gate. It must match a module-owned SKILL.md too — that is the
|
|
@@ -170,7 +190,8 @@ function format(report, { relTo = REPO_ROOT } = {}) {
|
|
|
170
190
|
}
|
|
171
191
|
const errs = report.results.reduce((a, r) => a + r.errors.length, 0);
|
|
172
192
|
const warns = report.results.reduce((a, r) => a + r.warnings.length, 0);
|
|
173
|
-
|
|
193
|
+
const resident = report.listedSkills !== undefined && report.listedSkills !== report.results.length ? ` (the ${report.listedSkills} resident here; the rest belong to modules this instance leaves off)` : '';
|
|
194
|
+
out.push(`skill-lint: ${report.results.length} skill(s), ${errs} error(s), ${warns} warning(s); listing ${report.listingChars} chars${resident} (~${Math.round(report.listingChars / 4)} tokens) vs ~${report.budgetChars}-char budget${report.overBudget ? ' — OVER: entries get truncated and routing degrades' : ''}`);
|
|
174
195
|
return out.join('\n');
|
|
175
196
|
}
|
|
176
197
|
|
|
@@ -196,10 +217,11 @@ function main() {
|
|
|
196
217
|
return;
|
|
197
218
|
}
|
|
198
219
|
const files = argv.filter((a) => !a.startsWith('--'));
|
|
199
|
-
const
|
|
220
|
+
const all = files.length ? null : listSkillFiles();
|
|
221
|
+
const report = all ? lintSkills(all, { resident: residentSkillFiles(REPO_ROOT, { files: all }) }) : lintSkills(files.map((f) => path.resolve(f)));
|
|
200
222
|
if (json) console.log(JSON.stringify(report, null, 1)); else console.log(format(report));
|
|
201
223
|
process.exitCode = report.results.some((r) => r.errors.length) ? 1 : 0;
|
|
202
224
|
}
|
|
203
225
|
|
|
204
|
-
module.exports = { lintFrontmatter, lintSkillFile, lintSkills, listSkillFiles, splitFrontmatter, isSkillMd, format, DESC_WARN_CHARS, DESC_HARD_CHARS, LISTING_BUDGET_CHARS };
|
|
226
|
+
module.exports = { lintFrontmatter, lintSkillFile, lintSkills, listSkillFiles, residentSkillFiles, splitFrontmatter, isSkillMd, format, DESC_WARN_CHARS, DESC_HARD_CHARS, LISTING_BUDGET_CHARS };
|
|
205
227
|
if (require.main === module) main();
|
|
@@ -269,8 +269,9 @@ const MODULE_GLOBS = {
|
|
|
269
269
|
// than instance hosting and the web-surface precedent is one key per surface.
|
|
270
270
|
'public-landing': ['modules/public-landing/'],
|
|
271
271
|
// --- the design capability (task 1003324, ADR 0197): the design contract, its
|
|
272
|
-
// adapters + sync CLIs + validator, the /design playbook, and the
|
|
273
|
-
//
|
|
272
|
+
// adapters + sync CLIs + validator, the /design playbook, the kit and the style
|
|
273
|
+
// library (the design-style skills are the design-styles key since task
|
|
274
|
+
// 1004470). default-on,
|
|
274
275
|
// declaration-only (three skills, no routes/port/migrations). The three
|
|
275
276
|
// scripts/gds/ shims are core-side entry points over the module's CLIs —
|
|
276
277
|
// listed for task affinity (the memory/ideas precedent: a command travels with
|
|
@@ -302,6 +303,11 @@ const MODULE_GLOBS = {
|
|
|
302
303
|
'modules/game/', 'src/preview-server.js',
|
|
303
304
|
],
|
|
304
305
|
'art-pipeline': ['modules/art-pipeline/'],
|
|
306
|
+
// --- the two opt-in SKILL modules (task 1004470): declaration-only, default-off.
|
|
307
|
+
// Each owns only its own dir — the skills ship from modules/<key>/skills/,
|
|
308
|
+
// not .claude/skills/, so there is no core skill dir to list. ---
|
|
309
|
+
'pixel-art': ['modules/pixel-art/'],
|
|
310
|
+
'design-styles': ['modules/design-styles/'],
|
|
305
311
|
// --- the COPY half of the design contract: the artist's loop over user-facing
|
|
306
312
|
// TEXT (goal 1000074). ADR 0081 gave design TOKENS a repo-owned source of
|
|
307
313
|
// truth; text had none. R01 built the inventory (the copy-inventory
|
package/src/module-api.js
CHANGED
|
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
|
|
|
75
75
|
// MAJOR (see allowBoxScope below): passes the request through untouched.
|
|
76
76
|
function deprecatedNoopMiddleware(_req, _res, next) { next(); }
|
|
77
77
|
|
|
78
|
-
const CORE_VERSION = '1.20.
|
|
78
|
+
const CORE_VERSION = '1.20.41'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
|
|
79
79
|
|
|
80
80
|
// A namespaced logger so a module's log lines are attributable + consistent.
|
|
81
81
|
// Usage: const log = api.logger('discord'); log.info('mounted');
|
|
@@ -507,10 +507,12 @@ t('moduleSkillSources: a non-slug name never reaches path.join; a vendored dir w
|
|
|
507
507
|
t('materializeClaude: copied hooks carry NO founder origin/config-dir; a disabled-module skill is excluded', () => {
|
|
508
508
|
if (!existsSync(join(ROOT, '.claude', 'hooks'))) return;
|
|
509
509
|
const dir = mkdtempSync(join(tmpdir(), 'rb-e2e-'));
|
|
510
|
-
// Target instance: demo-branded, art
|
|
510
|
+
// Target instance: demo-branded, pixel-art OFF (so its otb-* skills must be dropped).
|
|
511
|
+
// Since task 1004470 those skills are the pixel-art module's (they were orphans in the
|
|
512
|
+
// core's .claude/skills/ that art-pipeline, which has no manifest here, never owned).
|
|
511
513
|
mkdirSync(join(dir, 'config'), { recursive: true });
|
|
512
514
|
writeFileSync(join(dir, 'config', 'branding.json'), JSON.stringify({ domains: { publicOrigin: 'https://demo.cloudbongos.com', buildersOrigin: 'https://demo.cloudbongos.com', statusOrigin: 'https://demo.cloudbongos.com', oauthOrigin: 'https://demo.cloudbongos.com' }, configDir: 'cloudbongos', envPrefix: 'BONGOS' }));
|
|
513
|
-
writeFileSync(join(dir, 'config', 'modules.json'), JSON.stringify({ modules: { 'art-pipeline': false } }));
|
|
515
|
+
writeFileSync(join(dir, 'config', 'modules.json'), JSON.stringify({ modules: { 'art-pipeline': false, 'pixel-art': false } }));
|
|
514
516
|
const res = m.materializeClaude({ coreRoot: ROOT, instanceDir: dir, dryRun: false });
|
|
515
517
|
// Founder core → demo: a branding delta exists and rules are built. The NEUTRAL
|
|
516
518
|
// core now carries its own dev-loop hooks (task 1003125), so this body runs there
|
|
@@ -531,12 +533,11 @@ t('materializeClaude: copied hooks carry NO founder origin/config-dir; a disable
|
|
|
531
533
|
}
|
|
532
534
|
assert.deepEqual(offenders, [], `founder origin/config-dir survived in: ${offenders.join(', ')}`);
|
|
533
535
|
|
|
534
|
-
// (b) art
|
|
535
|
-
//
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
}
|
|
536
|
+
// (b) pixel-art is off → its otb-* skills are excluded; a core skill remains. This used
|
|
537
|
+
// to self-scope to a founder core, the only place an art-pipeline manifest existed;
|
|
538
|
+
// the pixel-art module ships in the neutral core, so it now runs everywhere.
|
|
539
|
+
assert.ok(res.excludedSkills.includes('otb-tile-generate'), `pixel-art skill excluded (got ${res.excludedSkills.join(',')})`);
|
|
540
|
+
assert.ok(!existsSync(join(dir, '.claude', 'skills', 'otb-tile-generate')), 'excluded skill not written');
|
|
540
541
|
assert.ok(existsSync(join(dir, '.claude', 'skills', 'builder-ship')), 'a core skill is still materialized');
|
|
541
542
|
rmSync(dir, { recursive: true, force: true });
|
|
542
543
|
});
|
package/tests/module_loader.mjs
CHANGED
|
@@ -276,7 +276,7 @@ test('the live tree discovers the extracted modules cleanly (BV1.R43/R48/R47/R49
|
|
|
276
276
|
// That is precisely how the agents regression reached an open PR (task 1002485).
|
|
277
277
|
loader._reset();
|
|
278
278
|
const snap = loader.loaderSnapshot();
|
|
279
|
-
assert.deepEqual(snap.loaded, ['agents', 'autonomy', 'builder-settings', 'copy-desk', 'discord', 'economy', 'government', 'grading', 'hall-ui', 'ideas', 'lifecycle', 'memory', 'npm-release', 'onboarding', 'platform-identity', 'provisioning', 'public-landing', 'render-deploy', 'security', 'sessions', 'specialities', 'status-ui', 'ui-design']);
|
|
279
|
+
assert.deepEqual(snap.loaded, ['agents', 'autonomy', 'builder-settings', 'copy-desk', 'design-styles', 'discord', 'economy', 'government', 'grading', 'hall-ui', 'ideas', 'lifecycle', 'memory', 'npm-release', 'onboarding', 'pixel-art', 'platform-identity', 'provisioning', 'public-landing', 'render-deploy', 'security', 'sessions', 'specialities', 'status-ui', 'ui-design']);
|
|
280
280
|
assert.deepEqual(snap.errors, []);
|
|
281
281
|
assert.deepEqual(snap.skipped, []);
|
|
282
282
|
loader._reset();
|
|
@@ -159,6 +159,16 @@ test('a cookie for a preview that is not running is dropped and the live hall an
|
|
|
159
159
|
}
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
+
test('the clearing cookie repeats the set attributes, Secure included (task 1004466)', () => {
|
|
163
|
+
const { setCookie } = require('../modules/npm-release/preview/divert.js');
|
|
164
|
+
for (const secure of [false, true]) {
|
|
165
|
+
const req = { secure };
|
|
166
|
+
const attrs = (c) => c.split('; ').slice(1).filter((a) => !/^Max-Age=/.test(a)).join('; ');
|
|
167
|
+
assert.equal(attrs(clearCookie(req)), attrs(setCookie('1.19.1000', req)), 'secure=' + secure);
|
|
168
|
+
assert.equal(/; Secure$/.test(clearCookie(req)), secure);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
162
172
|
test('the clearing cookie expires the steering cookie for the whole site', () => {
|
|
163
173
|
assert.match(clearCookie(), /^bongos_preview=; Path=\/; Max-Age=0/);
|
|
164
174
|
});
|