@event4u/agent-config 16.1.0 → 16.3.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 +98 -257
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +5 -5
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1862 -809
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +132 -80
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +7972 -5186
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2226 -1055
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +40913 -34865
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +29 -0
- package/dist/shared/skillRanking.js +74 -13
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/contracts/settings-classes.md +10 -6
- package/package.json +4 -4
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +91 -22
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +327 -3
- package/src/config/gate-violation-baselines.json +21 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +8 -3
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +38 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +28 -90
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +600 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +573 -25
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +621 -22
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +138 -7
- package/src/scripts/check_generator_sync.ts +71 -0
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +89 -9
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +90 -14
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +192 -14
- package/src/scripts/hooks/block_config_weakening.ts +294 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +100 -9
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +77 -71
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +1 -2
- package/src/scripts/hooks/exit_codes.ts +129 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +146 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +765 -68
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +70 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +75 -189
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +108 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +7 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +421 -17
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -7
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +41 -0
- package/src/shared/skillRanking.ts +117 -11
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
- package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
|
@@ -27,7 +27,10 @@
|
|
|
27
27
|
* `existing-ui-audit` skill (R3 Phase 2). `null` while the audit
|
|
28
28
|
* has not run; populated dict once the skill returns. `greenfield`
|
|
29
29
|
* flag plus `greenfield_decision` carry the user's scaffolding
|
|
30
|
-
* pick
|
|
30
|
+
* pick; `component_taxonomy` and `component_root` carry the
|
|
31
|
+
* granularity taxonomy the project itself evidences, or `'none'`.
|
|
32
|
+
* `'none'` is the value that leaves every downstream step behaving
|
|
33
|
+
* exactly as it did before detection existed. The audit gate (`work_engine.directives.ui.audit`)
|
|
31
34
|
* refuses to advance to design/apply while the slot is empty or
|
|
32
35
|
* while `greenfield` is set without a recorded decision.
|
|
33
36
|
* - `app_spec` — optional greenfield grounding artifact written by
|
|
@@ -40,7 +43,12 @@
|
|
|
40
43
|
* - `ui_design` — optional design brief produced by
|
|
41
44
|
* `work_engine.directives.ui.design` (R3 Phase 3 Step 1). Locks
|
|
42
45
|
* layout / components / states / microcopy / a11y; `design_confirmed`
|
|
43
|
-
* carries the user's sign-off.
|
|
46
|
+
* carries the user's sign-off. A `components[]` entry MAY carry a
|
|
47
|
+
* `tier` naming one of `ui_audit.component_taxonomy`'s tiers; the
|
|
48
|
+
* apply step reads it to name the target directory, and it is the
|
|
49
|
+
* only producer of that field. Omit it and the component is
|
|
50
|
+
* reported as a conformance gap rather than placed, which is the
|
|
51
|
+
* honest answer when nothing said where it belongs.
|
|
44
52
|
* - `ui_scaffold` — optional greenfield scaffold plan written by
|
|
45
53
|
* `work_engine.directives.ui.scaffold` (greenfield-scaffold
|
|
46
54
|
* Phase 3). Plan-only and stack-agnostic
|
|
@@ -172,6 +180,37 @@ export const KNOWN_DIRECTIVE_SETS: ReadonlySet<string> = new Set([
|
|
|
172
180
|
'mixed',
|
|
173
181
|
]);
|
|
174
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Every value `state.ui_audit.greenfield_decision` may carry.
|
|
185
|
+
*
|
|
186
|
+
* One list, read by the schema here and by the halt that offers the options
|
|
187
|
+
* (`directives/ui/audit.ts`), so an option the user can pick and a value the
|
|
188
|
+
* schema accepts cannot drift apart.
|
|
189
|
+
*
|
|
190
|
+
* `granularity_convention` is option 4: scaffold, and organise what is
|
|
191
|
+
* scaffolded under a named granularity convention. It is a fourth value of the
|
|
192
|
+
* same single-number question rather than a second axis — one number still
|
|
193
|
+
* answers the block, which is what the reply-shape rule requires.
|
|
194
|
+
*/
|
|
195
|
+
export const GREENFIELD_DECISIONS: ReadonlyArray<string> = [
|
|
196
|
+
'scaffold',
|
|
197
|
+
'bare',
|
|
198
|
+
'external_reference',
|
|
199
|
+
'granularity_convention',
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The greenfield pick that adopts a component-granularity convention.
|
|
204
|
+
*
|
|
205
|
+
* Exported HERE, beside the list it belongs to, and imported by every gate
|
|
206
|
+
* that tests for it — the audit halt that offers it, and the scaffold and
|
|
207
|
+
* app-spec gates that must let it through. It was a bare string literal in
|
|
208
|
+
* four places; a rename would have left those gates silently not matching,
|
|
209
|
+
* and an inert scaffold gate returns SUCCESS, so picking option 4 would have
|
|
210
|
+
* scaffolded nothing with no error anywhere.
|
|
211
|
+
*/
|
|
212
|
+
export const GRANULARITY_CONVENTION = 'granularity_convention';
|
|
213
|
+
|
|
175
214
|
/** Raised when a state payload violates the v1 contract. */
|
|
176
215
|
export class SchemaError extends Error {
|
|
177
216
|
constructor(message: string) {
|
|
@@ -535,7 +574,7 @@ function _validate_stack(stack: JsonValue): void {
|
|
|
535
574
|
* skill returns but before findings land; the gate treats it the
|
|
536
575
|
* same as `null`. Once populated, `greenfield` (when present)
|
|
537
576
|
* must be a bool, and `greenfield_decision` (when present) must
|
|
538
|
-
* be one of
|
|
577
|
+
* be one of `GREENFIELD_DECISIONS`. Other keys (`components`,
|
|
539
578
|
* `patterns`, ...) are validated by the audit handler against the
|
|
540
579
|
* skill contract — the schema only enforces shape, not content.
|
|
541
580
|
*/
|
|
@@ -559,16 +598,27 @@ function _validate_ui_audit(ui_audit: JsonValue): void {
|
|
|
559
598
|
: null;
|
|
560
599
|
if (
|
|
561
600
|
decision !== null &&
|
|
562
|
-
decision
|
|
563
|
-
decision !== 'bare' &&
|
|
564
|
-
decision !== 'external_reference'
|
|
601
|
+
!(typeof decision === 'string' && GREENFIELD_DECISIONS.includes(decision))
|
|
565
602
|
) {
|
|
566
603
|
throw new SchemaError(
|
|
567
604
|
`state.ui_audit.greenfield_decision must be one of ` +
|
|
568
|
-
`'
|
|
605
|
+
`${GREENFIELD_DECISIONS.map((d) => `'${d}'`).join(', ')}, or null; ` +
|
|
569
606
|
`got ${pyRepr(decision)}`,
|
|
570
607
|
);
|
|
571
608
|
}
|
|
609
|
+
const taxonomy = 'component_taxonomy' in ui_audit ? ui_audit['component_taxonomy'] : null;
|
|
610
|
+
if (taxonomy !== null && typeof taxonomy !== 'string') {
|
|
611
|
+
throw new SchemaError(
|
|
612
|
+
'state.ui_audit.component_taxonomy must be a string when present ' +
|
|
613
|
+
"— the project's own tiers joined with '/', or 'none'",
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
const root = 'component_root' in ui_audit ? ui_audit['component_root'] : null;
|
|
617
|
+
if (root !== null && typeof root !== 'string') {
|
|
618
|
+
throw new SchemaError(
|
|
619
|
+
'state.ui_audit.component_root must be a string when present',
|
|
620
|
+
);
|
|
621
|
+
}
|
|
572
622
|
if (
|
|
573
623
|
'a11y_baseline' in ui_audit &&
|
|
574
624
|
!Array.isArray(ui_audit['a11y_baseline'])
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component-granularity taxonomy detection from a project's own layout.
|
|
3
|
+
*
|
|
4
|
+
* Leaf module — stdlib only, NO intra-`work_engine` imports — so it can be
|
|
5
|
+
* called from a directive, a skill runner, or a test without pulling the
|
|
6
|
+
* engine in. Public API names stay snake_case to mirror the sibling detectors
|
|
7
|
+
* (`stack/detect.ts`, `stack/runner.ts`) 1:1, per ADR-200.
|
|
8
|
+
*
|
|
9
|
+
* What this answers, and what it deliberately does not:
|
|
10
|
+
*
|
|
11
|
+
* The question is *"has this project already chosen a way to organise its
|
|
12
|
+
* components by granularity, and if so what does it call the tiers?"* — never
|
|
13
|
+
* *"which taxonomy should this project use?"*. The recorded answer is the
|
|
14
|
+
* project's OWN tier directory names in the project's own order, joined with
|
|
15
|
+
* `/`, or {@link NO_TAXONOMY}. Nothing canonical is ever written into the
|
|
16
|
+
* record: a project with three tiers records three tiers, and a project whose
|
|
17
|
+
* tiers are called `primitives / patterns / features` records exactly that.
|
|
18
|
+
*
|
|
19
|
+
* That is the whole point of the module. The suite follows a taxonomy a
|
|
20
|
+
* project has chosen; it never forces one onto a project that has not.
|
|
21
|
+
*
|
|
22
|
+
* Why there is a lexicon at all, and what bounds it:
|
|
23
|
+
*
|
|
24
|
+
* Deciding *"is `components/checkout/` a granularity tier or a domain
|
|
25
|
+
* folder?"* cannot be done from structure alone — both are directories full of
|
|
26
|
+
* components. So {@link GRANULARITY_LEXICON} exists as a **recognition aid**:
|
|
27
|
+
* an unordered set of granularity words drawn from several vocabularies, with
|
|
28
|
+
* no ordering, no completeness claim, no level semantics, and no per-tier
|
|
29
|
+
* rules of any kind. It is read to answer "does this bucket name look like a
|
|
30
|
+
* granularity word", and for nothing else.
|
|
31
|
+
*
|
|
32
|
+
* In particular it is NEVER read when a component is placed: placement reads
|
|
33
|
+
* the recorded tier list by name (see `./place.ts`). A project whose tiers are
|
|
34
|
+
* in no lexicon still gets conformance, because a declaration in its own docs
|
|
35
|
+
* outranks inference — which is the path the `declared` fixture exercises.
|
|
36
|
+
*
|
|
37
|
+
* Evidence rules:
|
|
38
|
+
*
|
|
39
|
+
* 1. **Declared beats inferred.** A `## Component taxonomy` section in the
|
|
40
|
+
* project's `DESIGN.md` naming backticked directory names wins outright,
|
|
41
|
+
* provided at least {@link MIN_TIERS} of those names exist on disk under
|
|
42
|
+
* the component root. Grounding the declaration in the filesystem keeps a
|
|
43
|
+
* stale doc from declaring a taxonomy the tree does not have.
|
|
44
|
+
* 2. **Inference needs a majority, never a single hit.** At least
|
|
45
|
+
* {@link MIN_TIERS} immediate buckets under the component root must carry
|
|
46
|
+
* lexicon names, AND they must be at least {@link TIER_MAJORITY} of all
|
|
47
|
+
* buckets. One granularity-sounding folder among domain folders is a
|
|
48
|
+
* collision, not a convention — that is the false-positive direction the
|
|
49
|
+
* `collision` fixture pins.
|
|
50
|
+
* 3. **Anything else is {@link NO_TAXONOMY}.** A flat component folder, a
|
|
51
|
+
* missing component folder, an unreadable tree, a non-existent root: all
|
|
52
|
+
* record `none`, and the authoring step then behaves exactly as it does
|
|
53
|
+
* without this module.
|
|
54
|
+
*
|
|
55
|
+
* Detection never throws. A malformed doc, a permission error, or a missing
|
|
56
|
+
* directory degrades to `none` — the same recoverable-error contract as
|
|
57
|
+
* `stack/detect.ts`, and for the same reason: a wrong label is recoverable
|
|
58
|
+
* (the user can say so), a crash mid-dispatch is not. Degrading to `none` is
|
|
59
|
+
* also the *safe* direction here, because `none` is precisely the value that
|
|
60
|
+
* leaves the project's own structures untouched.
|
|
61
|
+
*/
|
|
62
|
+
import * as fs from 'node:fs';
|
|
63
|
+
import * as path from 'node:path';
|
|
64
|
+
|
|
65
|
+
/** Recorded value for a project that evidences no granularity taxonomy. */
|
|
66
|
+
export const NO_TAXONOMY = 'none';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Granularity words used to RECOGNISE a tier name — never to prescribe one.
|
|
70
|
+
*
|
|
71
|
+
* Drawn from several vocabularies rather than one, and read at exactly one
|
|
72
|
+
* place: {@link _infer_tiers}, which calls `.has()` and nothing else. It
|
|
73
|
+
* carries no level, no cap and no placement rule, and it is not consulted when
|
|
74
|
+
* a component is placed. A project is free to use names that appear nowhere
|
|
75
|
+
* here — it declares them, and the declaration wins.
|
|
76
|
+
*
|
|
77
|
+
* **Held ALPHABETICALLY, and that is load-bearing rather than tidy.** A
|
|
78
|
+
* JavaScript `Set` iterates in INSERTION order, so "it is a Set" proves
|
|
79
|
+
* nothing about ordering — an earlier draft of this file claimed exactly that
|
|
80
|
+
* while the first five entries were one vocabulary's five levels in their own
|
|
81
|
+
* sequence. Alphabetical order cannot be a level sequence, it is checkable,
|
|
82
|
+
* and a test asserts it. Iteration order is still never read for a decision.
|
|
83
|
+
*/
|
|
84
|
+
const _LEXICON_WORDS: ReadonlyArray<string> = [
|
|
85
|
+
'atom',
|
|
86
|
+
'block',
|
|
87
|
+
'cell',
|
|
88
|
+
'composite',
|
|
89
|
+
'element',
|
|
90
|
+
'layout',
|
|
91
|
+
'molecule',
|
|
92
|
+
'organism',
|
|
93
|
+
'page',
|
|
94
|
+
'part',
|
|
95
|
+
'particle',
|
|
96
|
+
'pattern',
|
|
97
|
+
'primitive',
|
|
98
|
+
'template',
|
|
99
|
+
'widget',
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
export const GRANULARITY_LEXICON: ReadonlySet<string> = new Set(_LEXICON_WORDS);
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Sibling folders that hold no components of their own tier.
|
|
106
|
+
*
|
|
107
|
+
* Excluded from the majority DENOMINATOR, never from the matches. A project
|
|
108
|
+
* that keeps `hooks/`, `utils/` and `types/` next to its tiers has not stopped
|
|
109
|
+
* using its tiers, but {@link COMPONENT_SUFFIXES} includes `.ts`, so those
|
|
110
|
+
* folders read as buckets and drag the share down: `atoms / molecules /
|
|
111
|
+
* organisms / hooks / utils / types` measured 3 of 6 and recorded `none`.
|
|
112
|
+
* Three ordinary sibling folders were enough to suppress a real taxonomy.
|
|
113
|
+
*/
|
|
114
|
+
export const SUPPORT_BUCKETS: ReadonlySet<string> = new Set([
|
|
115
|
+
'constant',
|
|
116
|
+
'context',
|
|
117
|
+
'helper',
|
|
118
|
+
'hook',
|
|
119
|
+
'icon',
|
|
120
|
+
'lib',
|
|
121
|
+
'provider',
|
|
122
|
+
'store',
|
|
123
|
+
'style',
|
|
124
|
+
'test',
|
|
125
|
+
'type',
|
|
126
|
+
'util',
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
/** Fewest tiers that can evidence a taxonomy. One name is a coincidence. */
|
|
130
|
+
export const MIN_TIERS = 2;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Share of a component root's buckets that must be tier-shaped to infer one.
|
|
134
|
+
*
|
|
135
|
+
* **Above two thirds, which is a measurement rather than a preference.** It
|
|
136
|
+
* sat at 0.6, and at 0.6 the ordinary kind-split `components/{layout, pages,
|
|
137
|
+
* forms}` measured 2 of 3 = 0.67 and was recorded as the taxonomy
|
|
138
|
+
* `layout/pages` — every `forms` component then a conformance gap, on a
|
|
139
|
+
* project that never chose a taxonomy at all. That is this roadmap's
|
|
140
|
+
* highest-ranked risk happening, so the floor is set above the 2-of-3 ratio
|
|
141
|
+
* that produced it. `layout`, `page`, `block`, `element`, `part` and `cell`
|
|
142
|
+
* are all ordinary folder names as well as granularity words, which is why a
|
|
143
|
+
* bare share is not enough on its own and {@link SUPPORT_BUCKETS} exists.
|
|
144
|
+
*
|
|
145
|
+
* It is NOT set higher: `atoms / molecules / organisms` beside one support
|
|
146
|
+
* folder is 3 of 4 = 0.75 and must still be found.
|
|
147
|
+
*/
|
|
148
|
+
export const TIER_MAJORITY = 0.7;
|
|
149
|
+
|
|
150
|
+
/** Directory names searched, in order, for the project's component root. */
|
|
151
|
+
export const COMPONENT_ROOT_CANDIDATES: ReadonlyArray<string> = [
|
|
152
|
+
'src/components',
|
|
153
|
+
'app/components',
|
|
154
|
+
'src/lib/components',
|
|
155
|
+
'src/app/components',
|
|
156
|
+
'resources/js/components',
|
|
157
|
+
'resources/views/components',
|
|
158
|
+
'app/javascript/components',
|
|
159
|
+
'components',
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Docs read for a declared convention, in order; the first QUALIFYING one wins.
|
|
164
|
+
*
|
|
165
|
+
* A doc with no `## Component taxonomy` section, or one naming fewer than
|
|
166
|
+
* {@link MIN_TIERS} tiers that exist on disk, falls through to the next.
|
|
167
|
+
*/
|
|
168
|
+
export const DECLARATION_DOCS: ReadonlyArray<string> = [
|
|
169
|
+
'DESIGN.md',
|
|
170
|
+
'docs/DESIGN.md',
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
/** Heading that opens a declared-taxonomy section, lower-cased. */
|
|
174
|
+
const DECLARATION_HEADING = 'component taxonomy';
|
|
175
|
+
|
|
176
|
+
/** File suffixes that make a file look like a component. */
|
|
177
|
+
const COMPONENT_SUFFIXES: ReadonlyArray<string> = [
|
|
178
|
+
'.tsx',
|
|
179
|
+
'.jsx',
|
|
180
|
+
'.vue',
|
|
181
|
+
'.svelte',
|
|
182
|
+
'.blade.php',
|
|
183
|
+
'.ts',
|
|
184
|
+
'.js',
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
/** Where the recorded taxonomy came from. */
|
|
188
|
+
export type TaxonomySource = 'declared' | 'inferred' | 'none';
|
|
189
|
+
|
|
190
|
+
/** What {@link detect_component_taxonomy} returns. */
|
|
191
|
+
export interface TaxonomyResult {
|
|
192
|
+
/**
|
|
193
|
+
* The single value the audit records in `state.ui_audit.component_taxonomy`
|
|
194
|
+
* — the project's own tiers joined with `/`, or {@link NO_TAXONOMY}.
|
|
195
|
+
*/
|
|
196
|
+
taxonomy: string;
|
|
197
|
+
/**
|
|
198
|
+
* The same tiers as a list.
|
|
199
|
+
*
|
|
200
|
+
* `declared` carries the DOCUMENT's order, which is the project's own.
|
|
201
|
+
* `inferred` carries alphabetical order, because bucket names arrive
|
|
202
|
+
* sorted and no filesystem fact states a level sequence. It reads as one
|
|
203
|
+
* for `atoms/molecules/organisms` by coincidence and would not for
|
|
204
|
+
* `pages/templates/organisms`. Nothing downstream reads the order.
|
|
205
|
+
*/
|
|
206
|
+
tiers: string[];
|
|
207
|
+
/** Component root relative to the project root, or `null` when none. */
|
|
208
|
+
component_root: string | null;
|
|
209
|
+
/** Which rule produced the answer. */
|
|
210
|
+
source: TaxonomySource;
|
|
211
|
+
/** Human-readable trace of what was read, for the audit's output. */
|
|
212
|
+
evidence: string[];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function _none(evidence: string[], component_root: string | null = null): TaxonomyResult {
|
|
216
|
+
return {
|
|
217
|
+
taxonomy: NO_TAXONOMY,
|
|
218
|
+
tiers: [],
|
|
219
|
+
component_root,
|
|
220
|
+
source: 'none',
|
|
221
|
+
evidence,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Detect the component-granularity taxonomy a project evidences.
|
|
227
|
+
*
|
|
228
|
+
* @param project_root Absolute or relative path to the project root.
|
|
229
|
+
* @returns A {@link TaxonomyResult}; never throws.
|
|
230
|
+
*/
|
|
231
|
+
export function detect_component_taxonomy(project_root: string): TaxonomyResult {
|
|
232
|
+
const evidence: string[] = [];
|
|
233
|
+
let component_root: string | null;
|
|
234
|
+
try {
|
|
235
|
+
component_root = _find_component_root(project_root);
|
|
236
|
+
} catch {
|
|
237
|
+
return _none(['component root unreadable']);
|
|
238
|
+
}
|
|
239
|
+
if (component_root === null) {
|
|
240
|
+
evidence.push(
|
|
241
|
+
`no component root under ${_display(project_root)} ` +
|
|
242
|
+
`(searched ${COMPONENT_ROOT_CANDIDATES.length} conventional paths)`,
|
|
243
|
+
);
|
|
244
|
+
return _none(evidence);
|
|
245
|
+
}
|
|
246
|
+
evidence.push(`component root: ${component_root}`);
|
|
247
|
+
|
|
248
|
+
let buckets: string[];
|
|
249
|
+
try {
|
|
250
|
+
buckets = _component_buckets(path.join(project_root, component_root));
|
|
251
|
+
} catch {
|
|
252
|
+
return _none([...evidence, 'component root unreadable'], component_root);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// `_declared_tiers` already applies the MIN_TIERS floor and returns `[]`
|
|
256
|
+
// below it, so re-testing the floor here would be a second copy of one
|
|
257
|
+
// invariant — the shape this branch removed from `apply.ts` for masking a
|
|
258
|
+
// regression in its own sibling. One owner; this asks only "was there one".
|
|
259
|
+
const declared = _declared_tiers(project_root, buckets, evidence);
|
|
260
|
+
if (declared.length > 0) {
|
|
261
|
+
return {
|
|
262
|
+
taxonomy: declared.join('/'),
|
|
263
|
+
tiers: declared,
|
|
264
|
+
component_root,
|
|
265
|
+
source: 'declared',
|
|
266
|
+
evidence,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const inferred = _infer_tiers(buckets, evidence);
|
|
271
|
+
if (inferred.length === 0) {
|
|
272
|
+
return _none(evidence, component_root);
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
taxonomy: inferred.join('/'),
|
|
276
|
+
tiers: inferred,
|
|
277
|
+
component_root,
|
|
278
|
+
source: 'inferred',
|
|
279
|
+
evidence,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** First conventional component directory that exists, or `null`. */
|
|
284
|
+
function _find_component_root(project_root: string): string | null {
|
|
285
|
+
for (const candidate of COMPONENT_ROOT_CANDIDATES) {
|
|
286
|
+
const full = path.join(project_root, ...candidate.split('/'));
|
|
287
|
+
let st: fs.Stats;
|
|
288
|
+
try {
|
|
289
|
+
st = fs.statSync(full);
|
|
290
|
+
} catch {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (st.isDirectory()) {
|
|
294
|
+
return candidate;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Immediate subdirectories of the component root that actually hold components.
|
|
302
|
+
*
|
|
303
|
+
* A directory with no component-shaped file anywhere beneath it is not a
|
|
304
|
+
* bucket — it is a stray folder, and counting it would drag the majority test
|
|
305
|
+
* around for reasons that have nothing to do with the project's convention.
|
|
306
|
+
*/
|
|
307
|
+
function _component_buckets(root: string): string[] {
|
|
308
|
+
const out: string[] = [];
|
|
309
|
+
for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
|
|
310
|
+
if (!entry.isDirectory()) continue;
|
|
311
|
+
if (entry.name.startsWith('.')) continue;
|
|
312
|
+
if (_holds_component(path.join(root, entry.name), 0)) {
|
|
313
|
+
out.push(entry.name);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
out.sort();
|
|
317
|
+
return out;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** True when a component-shaped file sits at or under `dir` (depth-capped). */
|
|
321
|
+
function _holds_component(dir: string, depth: number): boolean {
|
|
322
|
+
if (depth > 3) return false;
|
|
323
|
+
let entries: fs.Dirent[];
|
|
324
|
+
try {
|
|
325
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
326
|
+
} catch {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
for (const entry of entries) {
|
|
330
|
+
if (entry.isFile()) {
|
|
331
|
+
if (COMPONENT_SUFFIXES.some((s) => entry.name.endsWith(s))) {
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
} else if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
335
|
+
if (_holds_component(path.join(dir, entry.name), depth + 1)) {
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Tiers declared in the project's own docs, grounded against the tree.
|
|
345
|
+
*
|
|
346
|
+
* Reads the `## Component taxonomy` section of the first
|
|
347
|
+
* {@link DECLARATION_DOCS} hit and keeps the backticked names that exist as
|
|
348
|
+
* buckets. Order is the document's, because that is the project's own order.
|
|
349
|
+
*/
|
|
350
|
+
function _declared_tiers(
|
|
351
|
+
project_root: string,
|
|
352
|
+
buckets: string[],
|
|
353
|
+
evidence: string[],
|
|
354
|
+
): string[] {
|
|
355
|
+
const known = new Set(buckets);
|
|
356
|
+
for (const doc of DECLARATION_DOCS) {
|
|
357
|
+
let body: string;
|
|
358
|
+
try {
|
|
359
|
+
body = fs.readFileSync(path.join(project_root, ...doc.split('/')), 'utf8');
|
|
360
|
+
} catch {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
const section = _taxonomy_section(body);
|
|
364
|
+
if (section === null) {
|
|
365
|
+
evidence.push(`${doc}: no \`## Component taxonomy\` section`);
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
const named: string[] = [];
|
|
369
|
+
for (const line of section.split(/\r?\n/u)) {
|
|
370
|
+
// Only a list item declares a tier. A backticked name inside a
|
|
371
|
+
// prose sentence is a mention — the `legacy` fixture says in prose
|
|
372
|
+
// that it is NOT a tier, and a parser that scanned the whole
|
|
373
|
+
// section would enrol it on the strength of the backticks alone.
|
|
374
|
+
// `**` / `__` may lead the name: `- **\`alpha\`** — ...` is a
|
|
375
|
+
// completely ordinary way to write this list, and a regex that
|
|
376
|
+
// demanded the backtick lead dropped it silently.
|
|
377
|
+
const item = /^\s*(?:[-*+]|\d+[.)])\s+(?:\*\*|__)?`([^`\n]+)`/u.exec(line);
|
|
378
|
+
if (item === null) continue;
|
|
379
|
+
const name = (item[1] ?? '').trim();
|
|
380
|
+
// Grounded against the tree: a declaration cannot conjure a tier
|
|
381
|
+
// the project has not created.
|
|
382
|
+
if (name !== '' && known.has(name) && !named.includes(name)) {
|
|
383
|
+
named.push(name);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
if (named.length >= MIN_TIERS) {
|
|
387
|
+
evidence.push(`${doc}: declares ${named.length} tiers, all present on disk`);
|
|
388
|
+
return named;
|
|
389
|
+
}
|
|
390
|
+
evidence.push(
|
|
391
|
+
`${doc}: \`## Component taxonomy\` names ${named.length} tier(s) ` +
|
|
392
|
+
`present on disk — below the ${MIN_TIERS}-tier floor, so not a declaration`,
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** Body of the `## Component taxonomy` section, or `null` when absent. */
|
|
399
|
+
function _taxonomy_section(body: string): string | null {
|
|
400
|
+
const lines = body.split(/\r?\n/u);
|
|
401
|
+
let start = -1;
|
|
402
|
+
let level = 0;
|
|
403
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
404
|
+
const m = /^(#{1,6})\s+(.*)$/u.exec(lines[i] as string);
|
|
405
|
+
if (m === null) continue;
|
|
406
|
+
const heading = (m[2] ?? '').trim().toLowerCase().replace(/[:.]+$/u, '');
|
|
407
|
+
if (start === -1) {
|
|
408
|
+
if (heading === DECLARATION_HEADING) {
|
|
409
|
+
start = i + 1;
|
|
410
|
+
level = (m[1] as string).length;
|
|
411
|
+
}
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if ((m[1] as string).length <= level) {
|
|
415
|
+
return lines.slice(start, i).join('\n');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return start === -1 ? null : lines.slice(start).join('\n');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Tiers inferred from bucket names, or `[]` when the evidence is too thin.
|
|
423
|
+
*
|
|
424
|
+
* The only place {@link GRANULARITY_LEXICON} is consulted.
|
|
425
|
+
*/
|
|
426
|
+
function _infer_tiers(buckets: string[], evidence: string[]): string[] {
|
|
427
|
+
if (buckets.length === 0) {
|
|
428
|
+
evidence.push('component root has no sub-directories — flat layout');
|
|
429
|
+
return [];
|
|
430
|
+
}
|
|
431
|
+
const matched = buckets.filter((b) => GRANULARITY_LEXICON.has(_singular(b)));
|
|
432
|
+
const counted = buckets.filter((b) => !SUPPORT_BUCKETS.has(_singular(b)));
|
|
433
|
+
if (counted.length === 0) {
|
|
434
|
+
evidence.push('every bucket is a support folder — no tiers to weigh');
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
437
|
+
const share = matched.length / counted.length;
|
|
438
|
+
if (matched.length < MIN_TIERS || share < TIER_MAJORITY) {
|
|
439
|
+
evidence.push(
|
|
440
|
+
`${matched.length} of ${counted.length} weighed buckets carry granularity ` +
|
|
441
|
+
`names (need >= ${MIN_TIERS} and >= ${Math.round(TIER_MAJORITY * 100)}%; ` +
|
|
442
|
+
`${buckets.length - counted.length} support folder(s) not weighed) — ` +
|
|
443
|
+
'reads as domain folders, not a taxonomy',
|
|
444
|
+
);
|
|
445
|
+
return [];
|
|
446
|
+
}
|
|
447
|
+
evidence.push(
|
|
448
|
+
`${matched.length} of ${counted.length} weighed buckets carry granularity ` +
|
|
449
|
+
`names (${buckets.length - counted.length} support folder(s) not weighed) — ` +
|
|
450
|
+
'inferred from layout',
|
|
451
|
+
);
|
|
452
|
+
return matched;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Lower-case a bucket name and drop a trailing plural `s`.
|
|
457
|
+
*
|
|
458
|
+
* Deliberately naive: it exists so `atoms` matches `atom`, not to be a
|
|
459
|
+
* morphology engine. A name it mis-normalises simply fails to match, which
|
|
460
|
+
* lands on `none` — the safe direction.
|
|
461
|
+
*/
|
|
462
|
+
function _singular(name: string): string {
|
|
463
|
+
const lower = name.toLowerCase();
|
|
464
|
+
return lower.endsWith('s') && lower.length > 2 ? lower.slice(0, -1) : lower;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/** Trim a path for an evidence line so the trace stays readable. */
|
|
468
|
+
function _display(p: string): string {
|
|
469
|
+
const base = path.basename(p);
|
|
470
|
+
return base === '' ? p : base;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* CLI entry: print the detection result for a project root as JSON.
|
|
475
|
+
*
|
|
476
|
+
* `existing-ui-audit` § 1b tells the agent to RUN this file, so it has to be
|
|
477
|
+
* runnable. Without this block `npx tsx .../detect.ts` exited 0 and printed
|
|
478
|
+
* nothing, and an agent following the instruction literally got silence and
|
|
479
|
+
* then had to invent the two state keys the audit is supposed to record.
|
|
480
|
+
*
|
|
481
|
+
* ```bash
|
|
482
|
+
* npx tsx scripts/work_engine/taxonomy/detect.ts [--root <dir>]
|
|
483
|
+
* ```
|
|
484
|
+
*
|
|
485
|
+
* Defaults to the process CWD. Exits 0 whichever answer it reaches: `none` is
|
|
486
|
+
* a real answer here, not a failure, and an exit code that said otherwise
|
|
487
|
+
* would push a caller toward treating a no-taxonomy project as an error.
|
|
488
|
+
*/
|
|
489
|
+
export function main(argv: ReadonlyArray<string>): number {
|
|
490
|
+
const at = argv.indexOf('--root');
|
|
491
|
+
const root = at !== -1 && at + 1 < argv.length ? (argv[at + 1] as string) : process.cwd();
|
|
492
|
+
process.stdout.write(`${JSON.stringify(detect_component_taxonomy(root), null, 2)}\n`);
|
|
493
|
+
return 0;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Only when this module is the process entry, never on import. tsx sets
|
|
497
|
+
// `import.meta.url` to the entry file URL.
|
|
498
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
499
|
+
process.exitCode = main(process.argv.slice(2));
|
|
500
|
+
}
|