* feat(#896): Capability Registry generator + UI pilot (ADR-857 phase 3a-impl) First phase-3 code: the Capability Registry generation pipeline, built against the ADR-894 contract and NOT wired into the live loop (registry-only, per the staged-cutover design). - capabilities/ui/capability.json — the UI pilot (ADR-894 worked example): 2 skills, 2 agents, 3 config keys, 2 steps + 1 gate, with `when` activation. - scripts/gen-capability-registry.cjs — --write/--check generator. Hand-rolled schema validation (envelope + role-typed feature/runtime bodies + typed steps/contributions/gates + when + gate-check variants); cross-capability invariants (single ownership; requires exist+acyclic+tier-monotone; config-key ownership exclusive, collision-vs-central as a pending-migration warning); hooks validated against an inline LOOP_HOST_CONTRACT (3a-impl-2 swaps its source to the generated-from-workflows contract); GLOBAL point-ordered consumes-satisfiability; materialized byLoopPoint ordering (produces/consumes topo-sort); emits gsd-core/bin/lib/capability-registry.cjs (role-partitioned indexes + requiresClosure). Prototype-pollution guards (Object.create(null) + inline literal key checks) + fragment.path traversal guard. - gsd-core/bin/lib/capability-registry.cjs — committed generated artifact (mirrors package-identity.cjs: script-generated, tracked, linted, regenerated on build, drift-tested), wired via the new `gen:capability-registry` build step. - tests/capability-registry.test.cjs — 72 tests: schema + invariant + hook + ordering + adversarial (path-traversal, proto-pollution, runtime body, self-consume, cycles, collisions) + committed-file staleness guard. New-CLI-module checklist (INVENTORY 97->98, MANIFEST, ARCHITECTURE), CONTEXT.md "Capability Registry" un-[Planned]'d. Nothing wired into install/surface/loop. Gates: lint, code-review (4 bugs fixed), security-review (path-traversal + prototype-pollution fixed), codex adversarial-review ×3 (8+ findings fixed, confirmed sound), clean-build docker 13190 pass / 0 fail. Closes #896 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#896): CRLF-agnostic --check for capability-registry staleness (Windows) The committed capability-registry.cjs staleness guard failed on Windows CI only: git checks out the committed .cjs as CRLF (autocrlf, no .gitattributes) while the generator emits LF, so the byte-for-byte --check comparison mismatched. Normalize line endings on both sides of the --check comparison (no .gitattributes change, no change to the LF the generator writes). Adds a regression test simulating the Windows CRLF checkout. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
242 lines
4.5 KiB
JavaScript
242 lines
4.5 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* capability-registry.cjs — generated by scripts/gen-capability-registry.cjs
|
|
* DO NOT EDIT BY HAND. Run: node scripts/gen-capability-registry.cjs --write
|
|
* ADR-894 §5 — role-partitioned Capability Registry.
|
|
*/
|
|
|
|
const capabilities = {
|
|
"ui": {
|
|
"id": "ui",
|
|
"role": "feature",
|
|
"title": "UI design contracts",
|
|
"description": "UI-SPEC design contract + retrospective UI audit for frontend phases.",
|
|
"tier": "standard",
|
|
"requires": [],
|
|
"skills": [
|
|
"ui-phase",
|
|
"ui-review"
|
|
],
|
|
"agents": [
|
|
"gsd-ui-checker",
|
|
"gsd-ui-auditor"
|
|
],
|
|
"hooks": [],
|
|
"config": {
|
|
"workflow.ui_phase": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Enable the UI design-contract gate during planning."
|
|
},
|
|
"workflow.ui_review": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Enable the retrospective UI audit."
|
|
},
|
|
"workflow.ui_safety_gate": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Block execution on unmet UI-SPEC contracts."
|
|
}
|
|
},
|
|
"steps": [
|
|
{
|
|
"point": "plan:pre",
|
|
"ref": {
|
|
"skill": "ui-phase"
|
|
},
|
|
"produces": [
|
|
"UI-SPEC.md"
|
|
],
|
|
"consumes": [
|
|
"CONTEXT.md"
|
|
],
|
|
"when": "workflow.ui_phase",
|
|
"onError": "skip"
|
|
},
|
|
{
|
|
"point": "verify:post",
|
|
"ref": {
|
|
"skill": "ui-review"
|
|
},
|
|
"produces": [
|
|
"UI-REVIEW.md"
|
|
],
|
|
"consumes": [
|
|
"UI-SPEC.md"
|
|
],
|
|
"when": "workflow.ui_review",
|
|
"onError": "skip"
|
|
}
|
|
],
|
|
"contributions": [],
|
|
"gates": [
|
|
{
|
|
"point": "execute:wave:post",
|
|
"check": {
|
|
"query": "ui.safety-gate"
|
|
},
|
|
"when": "workflow.ui_safety_gate",
|
|
"blocking": true,
|
|
"onError": "halt"
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
const bySkill = {
|
|
"ui-phase": "ui",
|
|
"ui-review": "ui"
|
|
};
|
|
|
|
const byAgent = {
|
|
"gsd-ui-checker": "ui",
|
|
"gsd-ui-auditor": "ui"
|
|
};
|
|
|
|
const byLoopPoint = {
|
|
"discuss:pre": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"discuss:post": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"plan:pre": {
|
|
"steps": [
|
|
{
|
|
"capId": "ui",
|
|
"point": "plan:pre",
|
|
"ref": {
|
|
"skill": "ui-phase"
|
|
},
|
|
"produces": [
|
|
"UI-SPEC.md"
|
|
],
|
|
"consumes": [
|
|
"CONTEXT.md"
|
|
],
|
|
"when": "workflow.ui_phase",
|
|
"onError": "skip"
|
|
}
|
|
],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"plan:post": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"execute:pre": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"execute:wave:pre": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"execute:wave:post": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": [
|
|
{
|
|
"capId": "ui",
|
|
"point": "execute:wave:post",
|
|
"check": {
|
|
"query": "ui.safety-gate"
|
|
},
|
|
"when": "workflow.ui_safety_gate",
|
|
"blocking": true,
|
|
"onError": "halt"
|
|
}
|
|
]
|
|
},
|
|
"execute:post": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"verify:pre": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"verify:post": {
|
|
"steps": [
|
|
{
|
|
"capId": "ui",
|
|
"point": "verify:post",
|
|
"ref": {
|
|
"skill": "ui-review"
|
|
},
|
|
"produces": [
|
|
"UI-REVIEW.md"
|
|
],
|
|
"consumes": [
|
|
"UI-SPEC.md"
|
|
],
|
|
"when": "workflow.ui_review",
|
|
"onError": "skip"
|
|
}
|
|
],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"ship:pre": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
},
|
|
"ship:post": {
|
|
"steps": [],
|
|
"contributions": [],
|
|
"gates": []
|
|
}
|
|
};
|
|
|
|
const configKeys = {
|
|
"workflow.ui_phase": "ui",
|
|
"workflow.ui_review": "ui",
|
|
"workflow.ui_safety_gate": "ui"
|
|
};
|
|
|
|
const runtimes = {};
|
|
|
|
const _requiresGraph = {
|
|
"ui": []
|
|
};
|
|
|
|
function requiresClosure(id) {
|
|
const visited = new Set();
|
|
const queue = [id];
|
|
while (queue.length > 0) {
|
|
const current = queue.shift();
|
|
const reqs = _requiresGraph[current] || [];
|
|
for (const req of reqs) {
|
|
if (!visited.has(req)) {
|
|
visited.add(req);
|
|
queue.push(req);
|
|
}
|
|
}
|
|
}
|
|
return visited;
|
|
}
|
|
|
|
module.exports = {
|
|
version: '1',
|
|
capabilities,
|
|
bySkill,
|
|
byAgent,
|
|
byLoopPoint,
|
|
configKeys,
|
|
runtimes,
|
|
requiresClosure,
|
|
};
|