@event4u/agent-config 14.10.0 → 14.11.0
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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +335 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/design.md +88 -0
- package/dist/agent-src/commands/project/analyze.md +47 -0
- package/dist/agent-src/commands/review/changes.md +67 -6
- package/dist/agent-src/commands/roadmap/create.md +49 -0
- package/dist/agent-src/commands/roadmap/next.md +27 -11
- package/dist/agent-src/commands/roadmap/process-full.md +14 -0
- package/dist/agent-src/commands/video/from-script.md +60 -3
- package/dist/agent-src/commands/video/stitch.md +14 -0
- package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/rules/active-remediation.md +3 -3
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/context-hygiene.md +13 -33
- package/dist/agent-src/rules/council-availability.md +2 -2
- package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
- package/dist/agent-src/rules/design-fidelity.md +18 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
- package/dist/agent-src/rules/evaluator-independence.md +56 -44
- package/dist/agent-src/rules/fix-what-you-see.md +9 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
- package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
- package/dist/agent-src/rules/playbook-precedence.md +105 -0
- package/dist/agent-src/rules/recurring-criticism.md +3 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
- package/dist/agent-src/rules/scale-discipline.md +24 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
- package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
- package/dist/agent-src/rules/ui-audit-gate.md +27 -15
- package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
- package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
- package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
- package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
- package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
- package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
- package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
- package/dist/agent-src/skills/brand/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
- package/dist/agent-src/skills/code-review/SKILL.md +11 -0
- package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
- package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
- package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
- package/dist/agent-src/skills/design-review/SKILL.md +79 -1
- package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
- package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
- package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
- package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
- package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
- package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
- package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
- package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
- package/dist/agent-src/skills/iconography/SKILL.md +3 -0
- package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
- package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
- package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
- package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
- package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
- package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
- package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
- package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
- package/dist/agent-src/skills/override-management/SKILL.md +3 -0
- package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
- package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
- package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
- package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
- package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
- package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
- package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
- package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
- package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
- package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
- package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
- package/dist/agent-src/skills/terraform/SKILL.md +3 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
- package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
- package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
- package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
- package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
- package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/playbook.md +75 -0
- package/dist/agent-src/templates/roadmaps.md +37 -0
- package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/dist/cli/commands/uiAudit.js +221 -0
- package/dist/cli/commands/uiAudit.js.map +1 -0
- package/dist/cli/commands/uiRender.js +206 -0
- package/dist/cli/commands/uiRender.js.map +1 -0
- package/dist/cli/main.js +22 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/content.js +64 -1
- package/dist/cli/mcp/content.js.map +1 -1
- package/dist/cli/mcp/dispatch.js +175 -10
- package/dist/cli/mcp/dispatch.js.map +1 -1
- package/dist/cli/registry.js +3 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
- package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
- package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
- package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
- package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
- package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +8 -6
- package/dist/cli-delegate/cmd_conformance.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +70 -9
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +359 -124
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +18 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -6
- package/dist/hooks/dispatch.js +2337 -1436
- package/dist/install/install.mjs +795 -708
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1685 -1250
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/lean_projection_mode.js +40 -0
- package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
- package/dist/scripts/_lib/scoped_projection.js +84 -0
- package/dist/scripts/_lib/scoped_projection.js.map +1 -1
- package/dist/scripts/_lib/ui_surface.js +89 -0
- package/dist/scripts/_lib/ui_surface.js.map +1 -0
- package/dist/scripts/condense.js +6 -10
- package/dist/scripts/condense.js.map +1 -1
- package/dist/scripts/project_thin_rules.js +40 -2
- package/dist/scripts/project_thin_rules.js.map +1 -1
- package/dist/server/schemas/settings.js +3 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/skillRanking.js +159 -0
- package/dist/shared/skillRanking.js.map +1 -0
- package/docs/contracts/provider-lifecycle.md +47 -18
- package/docs/contracts/settings-classes.md +14 -4
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
- package/docs/guidelines/design-antipatterns.md +4 -2
- package/docs/guidelines/design-asset-discipline.md +38 -0
- package/docs/guidelines/design-fidelity-mechanics.md +45 -29
- package/docs/guidelines/design-handover-extraction.md +35 -5
- package/docs/guidelines/design-modes.md +41 -1
- package/docs/guidelines/monorepo-antipatterns.md +141 -0
- package/llms.txt +50 -39
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/src/config/agent-settings.template.yml +28 -0
- package/src/config/assurance-capability-registry.json +223 -0
- package/src/config/assurance-threshold-budget.json +65 -0
- package/src/config/ci-local-parity.yml +14 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/dispatch-economy-metrics.json +4 -2
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +207 -8
- package/src/config/gate-violation-baselines.json +76 -72
- package/src/config/hook-latency-budget.json +1 -0
- package/src/config/hook-token-budget.json +137 -125
- package/src/config/pack-size-budget.json +4 -2
- package/src/config/quorum-attendance-budget.json +12 -4
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/config/rule-stub-ceilings.json +112 -91
- package/src/scripts/_cli/cmd_doctor.ts +15 -16
- package/src/scripts/_cli/doctor_install_mode.ts +49 -0
- package/src/scripts/_cli/doctor_overrides.ts +154 -0
- package/src/scripts/_dispatch.bash +17 -0
- package/src/scripts/_lib/as_of.ts +412 -0
- package/src/scripts/_lib/exec_evidence.ts +7 -0
- package/src/scripts/_lib/hook_settings.ts +33 -0
- package/src/scripts/_lib/host_listing_model.ts +192 -0
- package/src/scripts/_lib/lean_projection_mode.ts +44 -0
- package/src/scripts/_lib/mcp_bridge.ts +199 -0
- package/src/scripts/_lib/review_independence.ts +62 -10
- package/src/scripts/_lib/rule_injection.ts +239 -0
- package/src/scripts/_lib/run_checkpoint.ts +54 -1
- package/src/scripts/_lib/scoped_projection.ts +96 -0
- package/src/scripts/_lib/session_register.ts +44 -2
- package/src/scripts/_lib/skill_catalogue.ts +38 -2
- package/src/scripts/_lib/transcript_reads.ts +207 -0
- package/src/scripts/_lib/ui_authority.test.ts +251 -0
- package/src/scripts/_lib/ui_authority.ts +343 -0
- package/src/scripts/ai-video/adapters/fal.sh +8 -3
- package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
- package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
- package/src/scripts/ai-video/adapters/kling.sh +10 -0
- package/src/scripts/ai-video/adapters/sora.sh +10 -0
- package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
- package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
- package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
- package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
- package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
- package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
- package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
- package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
- package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
- package/src/scripts/ai-video/smoke-trace.sh +450 -2
- package/src/scripts/ai-video/stitch.sh +191 -10
- package/src/scripts/ai-video/test-pipeline.sh +84 -6
- package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
- package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
- package/src/scripts/ai_council/clients.ts +3 -2
- package/src/scripts/ai_council/consensus.ts +63 -6
- package/src/scripts/ai_council/events_log.ts +46 -1
- package/src/scripts/ai_council/orchestrator.ts +103 -108
- package/src/scripts/ai_council/orchestrator_results.ts +166 -0
- package/src/scripts/ai_council/prompts.ts +12 -5
- package/src/scripts/ai_council/quorum.ts +82 -1
- package/src/scripts/ai_council/quorum_wiring.ts +82 -5
- package/src/scripts/ai_council/stance_tally.ts +22 -0
- package/src/scripts/bench_hook_latency.ts +62 -0
- package/src/scripts/build_proof.ts +12 -1
- package/src/scripts/capture_skill_catalogue.ts +21 -0
- package/src/scripts/check_always_budget.ts +2 -1
- package/src/scripts/check_augmentignore.ts +2 -1
- package/src/scripts/check_beta_review_markers.ts +2 -1
- package/src/scripts/check_composite_arming.ts +364 -0
- package/src/scripts/check_corpus_staleness.ts +2 -1
- package/src/scripts/check_council_pin_staleness.ts +3 -1
- package/src/scripts/check_enforcement_coverage.ts +116 -3
- package/src/scripts/check_enforcement_denominator.ts +365 -0
- package/src/scripts/check_gate_coverage.ts +2 -1
- package/src/scripts/check_hook_bundle_freshness.ts +13 -1
- package/src/scripts/check_knowledge_cards.ts +2 -1
- package/src/scripts/check_knowledge_pages.ts +3 -2
- package/src/scripts/check_memory.ts +2 -1
- package/src/scripts/check_no_automerge_key.ts +287 -0
- package/src/scripts/check_pack_conformance_fixture.ts +565 -0
- package/src/scripts/check_proposal.ts +2 -1
- package/src/scripts/check_reach_staleness.ts +2 -1
- package/src/scripts/check_release_adjacent_health.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +5 -0
- package/src/scripts/check_review_schema.ts +34 -1
- package/src/scripts/check_roadmap_trackable.ts +48 -3
- package/src/scripts/check_source_size_budget.ts +2 -1
- package/src/scripts/check_standing_payload_delta.ts +505 -0
- package/src/scripts/check_trigger_evals.ts +2 -1
- package/src/scripts/classify_change_risk.ts +281 -0
- package/src/scripts/compute_skill_tiers.ts +186 -0
- package/src/scripts/condense.ts +8 -13
- package/src/scripts/council_attendance_metrics.ts +183 -0
- package/src/scripts/council_cli.ts +10 -8
- package/src/scripts/council_parse_rate.ts +116 -0
- package/src/scripts/derive_playbooks.ts +406 -0
- package/src/scripts/design_slop_rules.test.ts +7 -0
- package/src/scripts/design_slop_rules.ts +56 -2
- package/src/scripts/dispatch_r2_reviewer.ts +16 -0
- package/src/scripts/frontend_corpus_hash.ts +116 -0
- package/src/scripts/grade_target_readiness.ts +478 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +97 -16
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/design_pass_hook.ts +356 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
- package/src/scripts/hooks/rule_inject_hook.ts +318 -0
- package/src/scripts/hot_context_hook.ts +74 -7
- package/src/scripts/install.ts +40 -89
- package/src/scripts/lint_adapter_tier.ts +663 -0
- package/src/scripts/lint_archived_skills.ts +93 -0
- package/src/scripts/lint_budget_ownership.ts +2 -1
- package/src/scripts/lint_deterministic_time.ts +470 -0
- package/src/scripts/lint_framework_leakage.ts +5 -0
- package/src/scripts/lint_handoffs.ts +525 -1
- package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
- package/src/scripts/lint_marketplace.ts +88 -0
- package/src/scripts/lint_media_policy_linkage.ts +140 -1
- package/src/scripts/lint_one_off_age.ts +6 -1
- package/src/scripts/lint_override_kernel_guard.ts +87 -5
- package/src/scripts/lint_roadmap_complexity.ts +56 -0
- package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
- package/src/scripts/lint_rule_norm_pin.ts +321 -0
- package/src/scripts/lint_spawn_payload.ts +42 -5
- package/src/scripts/lint_symptom_intake.ts +2 -1
- package/src/scripts/mcp_parity_smoke.ts +30 -4
- package/src/scripts/mcp_render.ts +66 -1
- package/src/scripts/mcp_tool_fingerprint.ts +241 -0
- package/src/scripts/measure_risk_class_drift.ts +140 -0
- package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
- package/src/scripts/media/lib/adapter-common.sh +211 -1
- package/src/scripts/media/lib/adapter-contract.md +74 -6
- package/src/scripts/model_rule_injection.ts +907 -0
- package/src/scripts/project_thin_rules.ts +45 -2
- package/src/scripts/release.ts +66 -860
- package/src/scripts/release_drill.ts +59 -3
- package/src/scripts/release_env.ts +298 -0
- package/src/scripts/release_publication.ts +720 -0
- package/src/scripts/roadmap_context.ts +778 -0
- package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +39 -0
- package/src/scripts/schemas/ui-authority.schema.json +114 -0
- package/src/scripts/session_register_hook.ts +29 -3
- package/src/scripts/sessions_cli.ts +67 -3
- package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
- package/src/scripts/token_sink_report.ts +239 -0
- package/src/scripts/trigger_coverage.ts +122 -3
- package/src/scripts/update_counts.ts +7 -3
- package/src/scripts/validate_frontmatter.ts +66 -0
- package/src/server/schemas/settings.ts +5 -0
- package/src/shared/skillRanking.ts +183 -0
|
@@ -42,10 +42,17 @@
|
|
|
42
42
|
* label is recoverable (audit catches it, user can override), but a
|
|
43
43
|
* crash mid-dispatch is not.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
* root
|
|
47
|
-
* a
|
|
48
|
-
*
|
|
45
|
+
* Workspace-aware since `road-to-monorepo-scope-and-detection`: a repository
|
|
46
|
+
* whose root declares workspaces (`package.json#workspaces`, a
|
|
47
|
+
* `pnpm-workspace.yaml`, a `turbo.json`, an `nx.json`, a `lerna.json`) and
|
|
48
|
+
* whose root manifest is not itself an application is descended into, and the
|
|
49
|
+
* workspace that was chosen is reported as {@link StackResult.scope_root}.
|
|
50
|
+
*
|
|
51
|
+
* The detector still never guesses **between** workspaces: two workspaces on
|
|
52
|
+
* mutually exclusive reactivity layers produce `unknown` plus both names, the
|
|
53
|
+
* same refusal a single conflicted manifest produces. What it no longer does is
|
|
54
|
+
* report `plain` for a monorepo — the previous behaviour, and the reason the
|
|
55
|
+
* repository was handed the generic directive.
|
|
49
56
|
*/
|
|
50
57
|
import * as fs from 'node:fs';
|
|
51
58
|
import * as path from 'node:path';
|
|
@@ -90,6 +97,8 @@ export const DEFAULT_STACK = 'plain';
|
|
|
90
97
|
export const UNSUPPORTED_STACK = 'unknown';
|
|
91
98
|
|
|
92
99
|
const _SHADCN_RADIX_PREFIX = '@radix-ui/';
|
|
100
|
+
/** The unified Radix package (February 2026) that replaced the `@radix-ui/*` scope. */
|
|
101
|
+
const _SHADCN_RADIX_UNIFIED = 'radix-ui';
|
|
93
102
|
const _SHADCN_PACKAGE_NAMES: ReadonlySet<string> = new Set(['shadcn-ui', 'shadcn']);
|
|
94
103
|
const _FLUX_PACKAGE = 'livewire/flux';
|
|
95
104
|
const _LIVEWIRE_PACKAGE = 'livewire/livewire';
|
|
@@ -193,16 +202,36 @@ export class StackResult {
|
|
|
193
202
|
*/
|
|
194
203
|
readonly ambiguity: ReadonlyArray<string>;
|
|
195
204
|
|
|
205
|
+
/**
|
|
206
|
+
* The workspace this result describes, **relative to the project root**.
|
|
207
|
+
*
|
|
208
|
+
* `''` means the project root itself — a non-monorepo, or a monorepo whose
|
|
209
|
+
* scope could not be resolved. Empty rather than `'.'` because that is
|
|
210
|
+
* already what `directives/ui/scaffold.ts` defaults to when the field is
|
|
211
|
+
* absent, so every non-monorepo project keeps byte-identical behaviour.
|
|
212
|
+
*
|
|
213
|
+
* Relative, not absolute, for two reasons that are both load-bearing. The
|
|
214
|
+
* field is serialized into `state.stack` and read back on a later run,
|
|
215
|
+
* possibly from a different absolute location (a container, a worktree, a
|
|
216
|
+
* moved checkout). And its one existing consumer — the playbook scope match
|
|
217
|
+
* at `scaffold.ts` — compares it against a playbook's declared `scope`,
|
|
218
|
+
* which is a repo-relative workspace path like `packages/ui`; an absolute
|
|
219
|
+
* path would silently match nothing but `scope: repo`.
|
|
220
|
+
*/
|
|
221
|
+
readonly scope_root: string;
|
|
222
|
+
|
|
196
223
|
constructor(args: {
|
|
197
224
|
frontend: string;
|
|
198
225
|
mtime: number;
|
|
199
226
|
axes?: StackAxes;
|
|
200
227
|
ambiguity?: ReadonlyArray<string>;
|
|
228
|
+
scope_root?: string;
|
|
201
229
|
}) {
|
|
202
230
|
this.frontend = args.frontend;
|
|
203
231
|
this.mtime = args.mtime;
|
|
204
232
|
this.axes = args.axes ?? _EMPTY_AXES;
|
|
205
233
|
this.ambiguity = args.ambiguity ?? [];
|
|
234
|
+
this.scope_root = args.scope_root ?? '';
|
|
206
235
|
}
|
|
207
236
|
}
|
|
208
237
|
|
|
@@ -241,6 +270,24 @@ export function detect_stack(project_root: string): StackResult {
|
|
|
241
270
|
return _r(UNSUPPORTED_STACK);
|
|
242
271
|
}
|
|
243
272
|
|
|
273
|
+
// Workspace root WITH a root manifest — the shape this detector was written
|
|
274
|
+
// for and never reached. The old guard was `mtime === 0.0`, i.e. "no
|
|
275
|
+
// manifest at the repository root at all", but a root `package.json` is the
|
|
276
|
+
// defining file of an npm/pnpm/yarn/bun workspace, so the branch was skipped
|
|
277
|
+
// for every repository it was meant to serve.
|
|
278
|
+
//
|
|
279
|
+
// The second half of the predicate is what keeps a root application out:
|
|
280
|
+
// a root that ships `react` in `dependencies` IS the app and must not be
|
|
281
|
+
// abandoned for one of its own packages. A root that ships `react` only in
|
|
282
|
+
// `devDependencies` beside a workspace declaration is shared test tooling,
|
|
283
|
+
// which is why the check reads runtime sections only.
|
|
284
|
+
if (_is_workspace_root(project_root, pkg) && !_root_carries_frontend(composer, pkg)) {
|
|
285
|
+
const scoped = _resolve_workspace_scope(project_root, mtime, axes);
|
|
286
|
+
if (scoped !== null) {
|
|
287
|
+
return scoped;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
244
291
|
if (_is_blade_livewire_flux(composer)) {
|
|
245
292
|
return _r('blade-livewire-flux');
|
|
246
293
|
}
|
|
@@ -279,39 +326,16 @@ export function detect_stack(project_root: string): StackResult {
|
|
|
279
326
|
return _r(UNSUPPORTED_STACK);
|
|
280
327
|
}
|
|
281
328
|
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
// dispatching generic tooling at it.
|
|
329
|
+
// No manifest at the repository root, but one sits in a workspace
|
|
330
|
+
// directory. Not a monorepo in the declarative sense — nothing declares the
|
|
331
|
+
// workspaces — but a scaffold in progress, and descending is still right.
|
|
286
332
|
//
|
|
287
333
|
// A repo with no manifest ANYWHERE stays `plain`: that is greenfield, and
|
|
288
334
|
// the scaffold path depends on it.
|
|
289
335
|
if (mtime === 0.0) {
|
|
290
|
-
const
|
|
291
|
-
if (
|
|
292
|
-
|
|
293
|
-
// axes. Refusing here would punish the common monorepo shape for a
|
|
294
|
-
// scope decision the layout already makes.
|
|
295
|
-
const inner = detect_stack(roots[0] as string);
|
|
296
|
-
return new StackResult({
|
|
297
|
-
frontend: inner.frontend,
|
|
298
|
-
mtime: inner.mtime,
|
|
299
|
-
axes: inner.axes,
|
|
300
|
-
ambiguity: inner.ambiguity,
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
if (roots.length > 1) {
|
|
304
|
-
// Several frontend roots: the caller owns scope selection, so name
|
|
305
|
-
// them and let the step ask. Picking the first would be the silent
|
|
306
|
-
// guess this detector exists to avoid.
|
|
307
|
-
return new StackResult({
|
|
308
|
-
frontend: UNSUPPORTED_STACK,
|
|
309
|
-
mtime,
|
|
310
|
-
axes,
|
|
311
|
-
ambiguity: [
|
|
312
|
-
`workspace roots: ${roots.map((r) => path.basename(r)).join(' + ')}`,
|
|
313
|
-
],
|
|
314
|
-
});
|
|
336
|
+
const scoped = _resolve_workspace_scope(project_root, mtime, axes);
|
|
337
|
+
if (scoped !== null) {
|
|
338
|
+
return scoped;
|
|
315
339
|
}
|
|
316
340
|
}
|
|
317
341
|
|
|
@@ -356,6 +380,13 @@ const _CACHE_KEY_FILES: ReadonlyArray<string> = [
|
|
|
356
380
|
'nuxt.config.ts',
|
|
357
381
|
'nuxt.config.js',
|
|
358
382
|
'astro.config.mjs',
|
|
383
|
+
// Workspace declarations, for exactly the reason `components.json` is here:
|
|
384
|
+
// adding a `pnpm-workspace.yaml` changes which manifest the result is
|
|
385
|
+
// computed from, while leaving both root manifests untouched — and the
|
|
386
|
+
// cache would otherwise serve the pre-workspace answer indefinitely.
|
|
387
|
+
'pnpm-workspace.yaml',
|
|
388
|
+
'turbo.json',
|
|
389
|
+
'nx.json',
|
|
359
390
|
];
|
|
360
391
|
|
|
361
392
|
/**
|
|
@@ -469,13 +500,35 @@ const _AXIS_SIGNALS: ReadonlyArray<{
|
|
|
469
500
|
|
|
470
501
|
// component_lib — marker file beats dependency
|
|
471
502
|
{ axis: 'component_lib', value: 'shadcn', npm: ['shadcn-ui', 'shadcn'], files: ['components.json'] },
|
|
472
|
-
|
|
503
|
+
// `radix-ui` (no slash) is the unified package shadcn's `new-york` style
|
|
504
|
+
// moved to in February 2026; the scoped `@radix-ui/*` packages are the
|
|
505
|
+
// pre-unification shape and both are still in the wild.
|
|
506
|
+
{ axis: 'component_lib', value: 'radix', npm: ['radix-ui'], npm_prefix: ['@radix-ui/'] },
|
|
507
|
+
// Base UI is the other primitive layer shadcn accepts. `@base-ui/react` is
|
|
508
|
+
// the name since Base UI 1.0; `@base-ui-components/react` is what it was
|
|
509
|
+
// called before the rename, and projects pinned to it still exist.
|
|
510
|
+
{ axis: 'component_lib', value: 'base-ui', npm: ['@base-ui/react', '@base-ui-components/react'] },
|
|
473
511
|
{ axis: 'component_lib', value: 'flux', composer: ['livewire/flux'] },
|
|
474
512
|
{ axis: 'component_lib', value: 'nuxt-ui', npm: ['@nuxt/ui'] },
|
|
475
513
|
{ axis: 'component_lib', value: 'vuetify', npm: ['vuetify'] },
|
|
476
514
|
{ axis: 'component_lib', value: 'mui', npm: ['@mui/material'] },
|
|
477
515
|
|
|
478
|
-
// css
|
|
516
|
+
// css — the major is a marker-file question, never a version string.
|
|
517
|
+
// v4 dropped `tailwind.config.*` in favour of CSS-first configuration, so
|
|
518
|
+
// the two majors are told apart by which artefact exists, and a project
|
|
519
|
+
// carrying neither marker stays on the undifferentiated `tailwind` value
|
|
520
|
+
// rather than being guessed into a major.
|
|
521
|
+
{ axis: 'css', value: 'tailwind-v4', npm: ['@tailwindcss/vite', '@tailwindcss/postcss'] },
|
|
522
|
+
{
|
|
523
|
+
axis: 'css',
|
|
524
|
+
value: 'tailwind-v3',
|
|
525
|
+
files: [
|
|
526
|
+
'tailwind.config.js',
|
|
527
|
+
'tailwind.config.cjs',
|
|
528
|
+
'tailwind.config.mjs',
|
|
529
|
+
'tailwind.config.ts',
|
|
530
|
+
],
|
|
531
|
+
},
|
|
479
532
|
{ axis: 'css', value: 'tailwind', npm: ['tailwindcss'] },
|
|
480
533
|
{ axis: 'css', value: 'bootstrap', npm: ['bootstrap'] },
|
|
481
534
|
];
|
|
@@ -564,6 +617,238 @@ function _detect_ambiguity(composer: Manifest, pkg: Manifest): string[] {
|
|
|
564
617
|
return found;
|
|
565
618
|
}
|
|
566
619
|
|
|
620
|
+
/** Files that declare a workspace root even when `package.json` does not. */
|
|
621
|
+
const _WORKSPACE_MARKER_FILES: ReadonlyArray<string> = [
|
|
622
|
+
'pnpm-workspace.yaml',
|
|
623
|
+
'pnpm-workspace.yml',
|
|
624
|
+
'turbo.json',
|
|
625
|
+
'nx.json',
|
|
626
|
+
'lerna.json',
|
|
627
|
+
];
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* True when `project_root` declares itself the root of a workspace.
|
|
631
|
+
*
|
|
632
|
+
* Declaration, not convention: the presence of an `apps/` directory is a guess,
|
|
633
|
+
* whereas `workspaces`, `pnpm-workspace.yaml`, `turbo.json`, `nx.json` and
|
|
634
|
+
* `lerna.json` are the repository saying so itself. The conventional-directory
|
|
635
|
+
* scan still exists one layer down in {@link _nested_frontend_roots}, as a
|
|
636
|
+
* fallback for the roots this predicate has already admitted.
|
|
637
|
+
*/
|
|
638
|
+
function _is_workspace_root(project_root: string, pkg: Manifest): boolean {
|
|
639
|
+
if (_workspace_globs(project_root, pkg).length > 0) {
|
|
640
|
+
return true;
|
|
641
|
+
}
|
|
642
|
+
return _WORKSPACE_MARKER_FILES.some((f) => _is_file(path.join(project_root, f)));
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* The declared workspace globs, from every declarative source.
|
|
647
|
+
*
|
|
648
|
+
* Three shapes, all real: npm/bun/yarn-modern's `workspaces: [...]`, yarn
|
|
649
|
+
* classic's `workspaces: { packages: [...] }`, and pnpm's `packages:` list in
|
|
650
|
+
* `pnpm-workspace.yaml` — the last of which a pnpm repository frequently has
|
|
651
|
+
* *instead of* any `workspaces` key at all.
|
|
652
|
+
*/
|
|
653
|
+
function _workspace_globs(project_root: string, pkg: Manifest): string[] {
|
|
654
|
+
const out: string[] = [];
|
|
655
|
+
const declared = pkg['workspaces'];
|
|
656
|
+
if (Array.isArray(declared)) {
|
|
657
|
+
out.push(...declared.filter((g): g is string => typeof g === 'string'));
|
|
658
|
+
} else if (_isDict(declared) && Array.isArray(declared['packages'])) {
|
|
659
|
+
out.push(
|
|
660
|
+
...(declared['packages'] as unknown[]).filter((g): g is string => typeof g === 'string'),
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
out.push(..._pnpm_workspace_globs(project_root));
|
|
664
|
+
return out;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/** Read the `packages:` globs out of `pnpm-workspace.yaml`. */
|
|
668
|
+
function _pnpm_workspace_globs(project_root: string): string[] {
|
|
669
|
+
for (const name of ['pnpm-workspace.yaml', 'pnpm-workspace.yml']) {
|
|
670
|
+
const p = path.join(project_root, name);
|
|
671
|
+
if (!_is_file(p)) {
|
|
672
|
+
continue;
|
|
673
|
+
}
|
|
674
|
+
let text: string;
|
|
675
|
+
try {
|
|
676
|
+
text = fs.readFileSync(p, { encoding: 'utf-8' });
|
|
677
|
+
} catch {
|
|
678
|
+
return [];
|
|
679
|
+
}
|
|
680
|
+
return _parse_pnpm_packages(text);
|
|
681
|
+
}
|
|
682
|
+
return [];
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Extract `packages:` from a `pnpm-workspace.yaml` body.
|
|
687
|
+
*
|
|
688
|
+
* Prefers the `yaml` package, lazily required exactly as
|
|
689
|
+
* `_lib/agent_settings.ts` does, so an exotic file (anchors, flow sequences,
|
|
690
|
+
* block scalars) parses properly. Falls back to a line scanner when `yaml`
|
|
691
|
+
* cannot be resolved — this module ships into consumer repositories that carry
|
|
692
|
+
* their own `node_modules`, and silently reading no globs there would
|
|
693
|
+
* reintroduce the very defect this branch exists to fix, for precisely the
|
|
694
|
+
* pnpm users it was written for.
|
|
695
|
+
*/
|
|
696
|
+
function _parse_pnpm_packages(text: string): string[] {
|
|
697
|
+
try {
|
|
698
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
699
|
+
const YAML = require('yaml') as { parse(input: string): unknown };
|
|
700
|
+
const data = YAML.parse(text);
|
|
701
|
+
if (_isDict(data) && Array.isArray(data['packages'])) {
|
|
702
|
+
return (data['packages'] as unknown[]).filter((g): g is string => typeof g === 'string');
|
|
703
|
+
}
|
|
704
|
+
return [];
|
|
705
|
+
} catch {
|
|
706
|
+
// `yaml` unresolvable, or the document did not parse — scan instead.
|
|
707
|
+
}
|
|
708
|
+
return _scan_yaml_string_list(text, 'packages');
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Read a top-level block sequence of strings out of a YAML document.
|
|
713
|
+
*
|
|
714
|
+
* Deliberately not a YAML parser. pnpm's own schema makes `packages` a flat
|
|
715
|
+
* list of glob strings, so the shape is fixed and a scanner cannot silently
|
|
716
|
+
* mis-read it the way a partial parser could.
|
|
717
|
+
*/
|
|
718
|
+
function _scan_yaml_string_list(text: string, key: string): string[] {
|
|
719
|
+
const out: string[] = [];
|
|
720
|
+
let inside = false;
|
|
721
|
+
for (const raw of text.split('\n')) {
|
|
722
|
+
const line = raw.replace(/\s+$/, '');
|
|
723
|
+
if (line === '' || line.trimStart().startsWith('#')) {
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (!inside) {
|
|
727
|
+
inside = line === `${key}:`;
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
const item = /^\s*-\s*(.+)$/.exec(line);
|
|
731
|
+
if (item === null) {
|
|
732
|
+
break; // the block ended
|
|
733
|
+
}
|
|
734
|
+
const value = (item[1] ?? '').trim().replace(/^['"]|['"]$/g, '');
|
|
735
|
+
if (value !== '') {
|
|
736
|
+
out.push(value);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return out;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* True when the root manifest describes an application rather than a container.
|
|
744
|
+
*
|
|
745
|
+
* Runtime sections only for `package.json`. A workspace root routinely carries
|
|
746
|
+
* a shared test or build setup in `devDependencies` — a Testing-Library stack,
|
|
747
|
+
* a bundler — and reading that as "the root is a React app" is how a Vue
|
|
748
|
+
* monorepo was handed a React lane before this check existed.
|
|
749
|
+
*/
|
|
750
|
+
function _root_carries_frontend(composer: Manifest, pkg: Manifest): boolean {
|
|
751
|
+
const php = _all_dependencies(composer, 'require', 'require-dev');
|
|
752
|
+
if (_LIVEWIRE_PACKAGE in php || _FILAMENT_PACKAGE in php) {
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
const runtime = _all_dependencies(pkg, 'dependencies', 'peerDependencies');
|
|
756
|
+
if ('react' in runtime || 'vue' in runtime) {
|
|
757
|
+
return true;
|
|
758
|
+
}
|
|
759
|
+
if (_UNMODELLED_MARKERS.some((marker) => marker in runtime || marker in php)) {
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
return Object.keys(runtime).some((name) => name.startsWith(_SHADCN_RADIX_PREFIX));
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Label specificity, most specific first — the label chain's own order.
|
|
767
|
+
*
|
|
768
|
+
* Used only to choose between workspaces that do NOT conflict. A monorepo whose
|
|
769
|
+
* app is `react` and whose design system is `react-shadcn` is one stack seen at
|
|
770
|
+
* two depths, and the deeper signal is the better scope for the UI lane: it is
|
|
771
|
+
* the package that owns `components.json`, which is where components are
|
|
772
|
+
* authored.
|
|
773
|
+
*/
|
|
774
|
+
const _LABEL_SPECIFICITY: ReadonlyArray<string> = [
|
|
775
|
+
'blade-livewire-flux',
|
|
776
|
+
'filament',
|
|
777
|
+
'blade-livewire',
|
|
778
|
+
'react-shadcn',
|
|
779
|
+
'react',
|
|
780
|
+
'vue',
|
|
781
|
+
UNSUPPORTED_STACK,
|
|
782
|
+
DEFAULT_STACK,
|
|
783
|
+
];
|
|
784
|
+
|
|
785
|
+
function _label_rank(label: string): number {
|
|
786
|
+
const i = _LABEL_SPECIFICITY.indexOf(label);
|
|
787
|
+
return i === -1 ? _LABEL_SPECIFICITY.length : i;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Pick the frontend scope inside a workspace repository, or refuse.
|
|
792
|
+
*
|
|
793
|
+
* `null` means "no workspace carries a frontend" — the caller falls through to
|
|
794
|
+
* its own label, which keeps a backend-only monorepo `plain` instead of
|
|
795
|
+
* inventing a scope for it.
|
|
796
|
+
*
|
|
797
|
+
* Workspaces that resolve to {@link DEFAULT_STACK} are dropped before anything
|
|
798
|
+
* else is decided. That is not a tidy-up: a normal Turborepo ships
|
|
799
|
+
* `packages/eslint-config` and `packages/typescript-config` beside the real
|
|
800
|
+
* ones, and counting those as "frontend roots" made the multi-root refusal fire
|
|
801
|
+
* on repositories that have exactly one frontend.
|
|
802
|
+
*/
|
|
803
|
+
function _resolve_workspace_scope(
|
|
804
|
+
project_root: string,
|
|
805
|
+
mtime: number,
|
|
806
|
+
root_axes: StackAxes,
|
|
807
|
+
): StackResult | null {
|
|
808
|
+
const candidates = _nested_frontend_roots(project_root)
|
|
809
|
+
.map((dir) => ({ dir, result: detect_stack(dir) }))
|
|
810
|
+
.filter((c) => c.result.frontend !== DEFAULT_STACK);
|
|
811
|
+
if (candidates.length === 0) {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Two workspaces on mutually exclusive reactivity layers are two stacks, and
|
|
816
|
+
// the standing contract for conflicting signals is to name them rather than
|
|
817
|
+
// pick one. Reuses `_EXCLUSIVE_REACTIVITY` so scope ambiguity and manifest
|
|
818
|
+
// ambiguity cannot drift apart: Alpine beside React is still one stack here,
|
|
819
|
+
// exactly as it is inside a single manifest.
|
|
820
|
+
const layers = new Set(
|
|
821
|
+
candidates
|
|
822
|
+
.map((c) => c.result.axes.reactivity)
|
|
823
|
+
.filter((value) => _EXCLUSIVE_REACTIVITY.has(value)),
|
|
824
|
+
);
|
|
825
|
+
if (layers.size > 1) {
|
|
826
|
+
const names = candidates
|
|
827
|
+
.map((c) => path.basename(c.dir))
|
|
828
|
+
.sort()
|
|
829
|
+
.join(' + ');
|
|
830
|
+
return new StackResult({
|
|
831
|
+
frontend: UNSUPPORTED_STACK,
|
|
832
|
+
mtime,
|
|
833
|
+
axes: root_axes,
|
|
834
|
+
ambiguity: [`workspace roots: ${names}`],
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const best = [...candidates].sort((a, b) => {
|
|
839
|
+
const delta = _label_rank(a.result.frontend) - _label_rank(b.result.frontend);
|
|
840
|
+
return delta !== 0 ? delta : a.dir.localeCompare(b.dir);
|
|
841
|
+
})[0] as { dir: string; result: StackResult };
|
|
842
|
+
|
|
843
|
+
return new StackResult({
|
|
844
|
+
frontend: best.result.frontend,
|
|
845
|
+
mtime: best.result.mtime,
|
|
846
|
+
axes: best.result.axes,
|
|
847
|
+
ambiguity: best.result.ambiguity,
|
|
848
|
+
scope_root: path.relative(project_root, best.dir),
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
|
|
567
852
|
/** Workspace directories a monorepo conventionally puts its packages in. */
|
|
568
853
|
const _WORKSPACE_DIRS: ReadonlyArray<string> = ['packages', 'apps', 'services', 'libs'];
|
|
569
854
|
|
|
@@ -584,10 +869,7 @@ function _nested_frontend_roots(project_root: string): string[] {
|
|
|
584
869
|
// `workspaces` is the declarative answer when present; the conventional
|
|
585
870
|
// directories are the fallback for repos that do not declare them.
|
|
586
871
|
const root_pkg = _read_json(path.join(project_root, 'package.json'));
|
|
587
|
-
const
|
|
588
|
-
const globs: string[] = Array.isArray(declared)
|
|
589
|
-
? (declared as unknown[]).filter((g): g is string => typeof g === 'string')
|
|
590
|
-
: [];
|
|
872
|
+
const globs = _workspace_globs(project_root, root_pkg);
|
|
591
873
|
const dirs = new Set<string>(_WORKSPACE_DIRS);
|
|
592
874
|
for (const g of globs) {
|
|
593
875
|
const head = g.split('/')[0];
|
|
@@ -640,7 +922,10 @@ function _is_react_shadcn(pkg: Manifest, components_json: boolean): boolean {
|
|
|
640
922
|
return false;
|
|
641
923
|
}
|
|
642
924
|
const names = Object.keys(deps);
|
|
643
|
-
|
|
925
|
+
// The unified `radix-ui` package counts exactly like the scoped `@radix-ui/*`
|
|
926
|
+
// prefix it replaced — same primitives, one entry in the manifest.
|
|
927
|
+
const has_radix =
|
|
928
|
+
_SHADCN_RADIX_UNIFIED in deps || names.some((name) => name.startsWith(_SHADCN_RADIX_PREFIX));
|
|
644
929
|
const has_shadcn_pkg = names.some((name) => _SHADCN_PACKAGE_NAMES.has(name));
|
|
645
930
|
return has_radix || has_shadcn_pkg || components_json;
|
|
646
931
|
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent-config ui:audit <path>` — inventory a UI tree into an artefact.
|
|
3
|
+
*
|
|
4
|
+
* Step E2.1 of `road-to-frontend-power`. Before this command, `state.ui_audit`
|
|
5
|
+
* existed only inside the work-engine dispatcher, which is why
|
|
6
|
+
* `src/rules/ui-audit-gate.md` shipped `enforced_by: none`: a chat session had
|
|
7
|
+
* nothing to point at, and "I ran the audit" is self-report. This writes the
|
|
8
|
+
* artefact a gate can read.
|
|
9
|
+
*
|
|
10
|
+
* CLASS A per `docs/decisions/ADR-124` and `docs/contracts/no-runtime-boundary.md`:
|
|
11
|
+
* it terminates, and its whole state is one rebuildable JSON file under
|
|
12
|
+
* `agents/runtime/state/`. Deleting the artefact changes only speed — the next
|
|
13
|
+
* invocation reproduces it. No process survives the command.
|
|
14
|
+
*
|
|
15
|
+
* The output shape is the one the work engine already expects for
|
|
16
|
+
* `state.ui_audit` (`components_found`, `greenfield`, `audit_path`), so the
|
|
17
|
+
* dispatcher and a chat session read the same object rather than two dialects.
|
|
18
|
+
* `COVERAGE_BUCKETS` is imported from the engine rather than re-listed here:
|
|
19
|
+
* `fe-design` step 3 already had a copied vocabulary, and a second copy is how
|
|
20
|
+
* the two drift.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately NOT a design opinion. This command reports what exists. Whether
|
|
23
|
+
* what exists is good is `design-review`'s job, and mixing the two would make
|
|
24
|
+
* the artefact's meaning depend on taste.
|
|
25
|
+
*/
|
|
26
|
+
import * as fs from 'node:fs';
|
|
27
|
+
import * as path from 'node:path';
|
|
28
|
+
import { isUiPath, isUiTreePath } from '../../scripts/_lib/ui_surface.js';
|
|
29
|
+
/**
|
|
30
|
+
* The engine's coverage vocabulary, declared here rather than re-exported.
|
|
31
|
+
*
|
|
32
|
+
* A re-export from `agent-src/templates/scripts/work_engine/...` was tried
|
|
33
|
+
* first and reverted: it creates a RUNTIME edge from the shipped CLI into the
|
|
34
|
+
* work-engine TEMPLATE tree, which is projected to consumers rather than
|
|
35
|
+
* compiled into `dist/cli`. The published bundle then fails to resolve it at
|
|
36
|
+
* import time — caught by `agent-config roadmap:progress` throwing
|
|
37
|
+
* ERR_MODULE_NOT_FOUND on a clean tree.
|
|
38
|
+
*
|
|
39
|
+
* The one-vocabulary guarantee survives without the edge: `uiAudit.test.ts`
|
|
40
|
+
* reads the engine's own `apply.ts` and asserts this array equals it, so drift
|
|
41
|
+
* is a red test rather than two copies quietly diverging. A test-time read into
|
|
42
|
+
* the template tree is fine — the tests already read it; a runtime import is
|
|
43
|
+
* not.
|
|
44
|
+
*/
|
|
45
|
+
export const COVERAGE_BUCKETS = ['honoured', 'translated', 'flagged'];
|
|
46
|
+
export const ARTEFACT_REL = path.join('agents', 'runtime', 'state', 'ui-audit.json');
|
|
47
|
+
/** Files that mark an adopted design system, and the marker each implies. */
|
|
48
|
+
const SYSTEM_MARKERS = [
|
|
49
|
+
[/components\/ui\/[a-z-]+\.tsx?$/i, 'shadcn'],
|
|
50
|
+
[/\btailwind\.config\.[cm]?[jt]s$/i, 'tailwind'],
|
|
51
|
+
[/\bDESIGN\.md$/, 'design-md'],
|
|
52
|
+
[/\bPRODUCT\.md$/, 'product-md'],
|
|
53
|
+
[/\btokens\.json$/, 'dtcg-tokens'],
|
|
54
|
+
[/\btokens\.css$/, 'css-tokens'],
|
|
55
|
+
];
|
|
56
|
+
const TOKEN_DECL = /(--[a-z0-9][a-z0-9-]*)\s*:/gi;
|
|
57
|
+
const FONT_FAMILY_DECL = /font-family\s*:\s*([^;}"'\n]*(?:"[^"]*"|'[^']*')?[^;}\n]*)/gi;
|
|
58
|
+
const JSX_EXPORT = /export\s+(?:default\s+)?(?:function|const|class)\s+([A-Z][A-Za-z0-9_]*)/g;
|
|
59
|
+
function walk(root, out = [], depth = 0) {
|
|
60
|
+
if (depth > 12)
|
|
61
|
+
return out;
|
|
62
|
+
let entries;
|
|
63
|
+
try {
|
|
64
|
+
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
70
|
+
if (e.name === 'node_modules' || e.name === '.git' || e.name === 'dist')
|
|
71
|
+
continue;
|
|
72
|
+
const p = path.join(root, e.name);
|
|
73
|
+
if (e.isDirectory())
|
|
74
|
+
walk(p, out, depth + 1);
|
|
75
|
+
else
|
|
76
|
+
out.push(p);
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
function classify(rel) {
|
|
81
|
+
if (/\.(css|scss|sass|less)$/i.test(rel))
|
|
82
|
+
return 'style';
|
|
83
|
+
if (/(^|\/)(pages|app)\//i.test(rel) || /(^|\/)(page|index)\.[jt]sx?$/i.test(rel))
|
|
84
|
+
return 'page';
|
|
85
|
+
if (/\.blade\.php$/.test(rel) || /resources\/views\//.test(rel))
|
|
86
|
+
return 'view';
|
|
87
|
+
return 'component';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Pure core. Takes (relative path, text) pairs so every branch is testable
|
|
91
|
+
* without a tree on disk — the same reason `ui_authority` takes a record.
|
|
92
|
+
*/
|
|
93
|
+
export function buildArtefact(root, files, now = new Date().toISOString()) {
|
|
94
|
+
const uiFiles = files.filter(([rel]) => isUiPath(rel) || isUiTreePath(rel));
|
|
95
|
+
const components = [];
|
|
96
|
+
const tokens = new Set();
|
|
97
|
+
const primitives = new Set();
|
|
98
|
+
const markers = [];
|
|
99
|
+
const families = new Set();
|
|
100
|
+
for (const [rel] of files) {
|
|
101
|
+
for (const [re, marker] of SYSTEM_MARKERS) {
|
|
102
|
+
if (re.test(rel) && !markers.some((m) => m.marker === marker))
|
|
103
|
+
markers.push({ marker, path: rel });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
for (const [rel, text] of uiFiles) {
|
|
107
|
+
for (const m of text.matchAll(TOKEN_DECL))
|
|
108
|
+
tokens.add(m[1].toLowerCase());
|
|
109
|
+
for (const m of text.matchAll(FONT_FAMILY_DECL)) {
|
|
110
|
+
const first = m[1].split(',')[0]?.trim().replace(/^["']|["']$/g, '').toLowerCase();
|
|
111
|
+
if (first && !first.startsWith('var('))
|
|
112
|
+
families.add(first);
|
|
113
|
+
}
|
|
114
|
+
const exports = [];
|
|
115
|
+
for (const m of text.matchAll(JSX_EXPORT)) {
|
|
116
|
+
exports.push(m[1]);
|
|
117
|
+
primitives.add(m[1]);
|
|
118
|
+
}
|
|
119
|
+
components.push({ path: rel, kind: classify(rel), exports });
|
|
120
|
+
}
|
|
121
|
+
// Greenfield is the ABSENCE of a UI surface, not the absence of a
|
|
122
|
+
// DESIGN.md. A1.3 depends on this distinction: a coherent incumbent with no
|
|
123
|
+
// DESIGN.md is emphatically not greenfield.
|
|
124
|
+
const greenfield = components.length === 0;
|
|
125
|
+
// Coherence is evidence of a consistent visual vocabulary, and it has more
|
|
126
|
+
// than one shape. Three independent signals, any of which is sufficient:
|
|
127
|
+
const signals = [];
|
|
128
|
+
if (tokens.size >= 3)
|
|
129
|
+
signals.push(`${tokens.size} declared tokens`);
|
|
130
|
+
if (markers.length > 0)
|
|
131
|
+
signals.push(`design-system marker: ${markers.map((m) => m.marker).join(', ')}`);
|
|
132
|
+
// A single dominant first-choice family is the signal the token heuristic
|
|
133
|
+
// misses entirely: a hand-written stylesheet can be perfectly coherent with
|
|
134
|
+
// literal values and BEM naming and declare no custom property at all.
|
|
135
|
+
if (families.size === 1)
|
|
136
|
+
signals.push(`single type family: ${[...families][0]}`);
|
|
137
|
+
const coherent = signals.length > 0;
|
|
138
|
+
return {
|
|
139
|
+
schema: 1,
|
|
140
|
+
generated_at: now,
|
|
141
|
+
root,
|
|
142
|
+
components_found: components,
|
|
143
|
+
tokens: [...tokens].sort(),
|
|
144
|
+
primitives: [...primitives].sort(),
|
|
145
|
+
design_system_markers: markers,
|
|
146
|
+
greenfield,
|
|
147
|
+
audit_path: greenfield ? 'greenfield' : coherent ? 'high_confidence' : 'ambiguous',
|
|
148
|
+
coherence_signals: signals,
|
|
149
|
+
context_stale: staleness(files, tokens),
|
|
150
|
+
verification: 'verified',
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* E2.3 — Tier-1 staleness, on data the command has ALREADY opened.
|
|
155
|
+
*
|
|
156
|
+
* The step's constraint is that the file-open count must not rise, which is why
|
|
157
|
+
* this takes the same `files` array rather than re-reading DESIGN.md. A token
|
|
158
|
+
* named in DESIGN.md or PRODUCT.md that no UI file declares is reported; it is
|
|
159
|
+
* never repaired here, because repairing a context document without being asked
|
|
160
|
+
* is a scope expansion, not a service.
|
|
161
|
+
*/
|
|
162
|
+
export function staleness(files, declared) {
|
|
163
|
+
const out = [];
|
|
164
|
+
for (const [rel, text] of files) {
|
|
165
|
+
if (!/\b(DESIGN|PRODUCT)\.md$/.test(rel))
|
|
166
|
+
continue;
|
|
167
|
+
for (const m of text.matchAll(/`(--[a-z0-9][a-z0-9-]*)`/gi)) {
|
|
168
|
+
const token = m[1].toLowerCase();
|
|
169
|
+
if (!declared.has(token)) {
|
|
170
|
+
out.push({ document: rel, token, reason: 'named in the document, declared by no UI file' });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
176
|
+
export function runUiAudit(opts = {}) {
|
|
177
|
+
const projectRoot = path.resolve(opts.projectRoot ?? process.cwd());
|
|
178
|
+
const target = path.resolve(projectRoot, opts.target ?? '.');
|
|
179
|
+
if (!fs.existsSync(target)) {
|
|
180
|
+
process.stderr.write(`[ui:audit] path not found: ${target}\n`);
|
|
181
|
+
return 1;
|
|
182
|
+
}
|
|
183
|
+
const stat = fs.statSync(target);
|
|
184
|
+
const absFiles = stat.isDirectory() ? walk(target) : [target];
|
|
185
|
+
const pairs = [];
|
|
186
|
+
let unreadable = 0;
|
|
187
|
+
for (const abs of absFiles) {
|
|
188
|
+
try {
|
|
189
|
+
if (fs.statSync(abs).size > 2_000_000)
|
|
190
|
+
continue;
|
|
191
|
+
pairs.push([path.relative(projectRoot, abs).split(path.sep).join('/'), fs.readFileSync(abs, 'utf8')]);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
unreadable++;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
let artefact = buildArtefact(path.relative(projectRoot, target).split(path.sep).join('/') || '.', pairs);
|
|
198
|
+
if (unreadable > 0) {
|
|
199
|
+
artefact = {
|
|
200
|
+
...artefact,
|
|
201
|
+
verification: 'degraded',
|
|
202
|
+
degradation_reason: `${unreadable} file(s) could not be read`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
const outPath = path.join(projectRoot, ARTEFACT_REL);
|
|
206
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
207
|
+
fs.writeFileSync(outPath, `${JSON.stringify(artefact, null, 2)}\n`);
|
|
208
|
+
if (opts.json)
|
|
209
|
+
process.stdout.write(`${JSON.stringify(artefact, null, 2)}\n`);
|
|
210
|
+
else {
|
|
211
|
+
process.stdout.write(`✅ ui:audit — ${artefact.components_found.length} component(s), ${artefact.tokens.length} token(s), ` +
|
|
212
|
+
`${artefact.design_system_markers.length} system marker(s); path=${artefact.audit_path}\n` +
|
|
213
|
+
` ${ARTEFACT_REL}\n` +
|
|
214
|
+
(artefact.context_stale.length
|
|
215
|
+
? ` ⚠️ ${artefact.context_stale.length} CONTEXT_STALE line(s) — reported, not repaired\n`
|
|
216
|
+
: '') +
|
|
217
|
+
(artefact.verification !== 'verified' ? ` ⚠️ ${artefact.degradation_reason}\n` : ''));
|
|
218
|
+
}
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=uiAudit.js.map
|