@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
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* check_host_format_column.ts — the compile-time (format) column of
|
|
4
|
+
* `docs/enforcement-by-host.md`'s host table may only name paths an emitter in
|
|
5
|
+
* this tree actually writes.
|
|
6
|
+
*
|
|
7
|
+
* WHY THIS EXISTS
|
|
8
|
+
* ---------------
|
|
9
|
+
* The Cursor cell read `.cursorrules` from the day the table was written until
|
|
10
|
+
* 2026-09-29. Nothing in this tree has ever written that file: the projection
|
|
11
|
+
* maps `.cursor/rules` (`condense.ts` `TOOL_DIRS`) and the install-time emitter
|
|
12
|
+
* writes `.cursor/rules/<name>.mdc` (`src/install/emit_host_rules_cli.ts`
|
|
13
|
+
* `emitCursor`). The cell was hand-maintained, nothing compared it to an
|
|
14
|
+
* emitter, and an external reader found it before any check did.
|
|
15
|
+
*
|
|
16
|
+
* A hand-maintained cell describing generated output is the defect. Correcting
|
|
17
|
+
* the cell once fixes today; this gate is what makes the NEXT drift a failing
|
|
18
|
+
* check rather than a reader's discovery.
|
|
19
|
+
*
|
|
20
|
+
* WHAT IT PROVES, AND WHAT IT DOES NOT
|
|
21
|
+
* ------------------------------------
|
|
22
|
+
* It proves every path the format column names is a path some emitter in this
|
|
23
|
+
* tree produces. It does NOT prove the converse — a host whose surface this
|
|
24
|
+
* package writes but whose cell omits it is not a finding here, because the
|
|
25
|
+
* cell is prose describing a host's native format and is allowed to name one
|
|
26
|
+
* representative surface rather than enumerate all of them. Nor does it say
|
|
27
|
+
* anything about whether a host READS what is written; that is a fact about the
|
|
28
|
+
* host and no gate in this repository can reach it.
|
|
29
|
+
*
|
|
30
|
+
* THE ORACLE — MEASURED FIRST, DECLARED SECOND, NEVER SCRAPED
|
|
31
|
+
* -----------------------------------------------------------
|
|
32
|
+
* The risk with a check like this is the inverse failure: it reds on a cell
|
|
33
|
+
* that is correct, gets disabled, and the column goes back to being
|
|
34
|
+
* hand-maintained — which is what produced the Cursor error in the first place.
|
|
35
|
+
* Scraping literal strings out of an emitter's source is how that happens,
|
|
36
|
+
* because targets built by interpolation never appear as literals. So the
|
|
37
|
+
* emitted set is built two ways and neither reads the emitters' text:
|
|
38
|
+
*
|
|
39
|
+
* 1. MEASURED. {@link measuredEmitterSurfaces} RUNS the two install-time rule
|
|
40
|
+
* emitters against a throwaway rules directory and walks what they left on
|
|
41
|
+
* disk. Interpolated or not, a path only enters the set if an emitter
|
|
42
|
+
* actually wrote it. This is the strongest half and it covers the two rows
|
|
43
|
+
* the original defect touched.
|
|
44
|
+
* 2. DECLARED. {@link declaredRoots} and {@link anchorDirs} import two
|
|
45
|
+
* registries the projection generators and the installer are already bound
|
|
46
|
+
* to — `ADAPTER_REGISTRY` (kept in step with the README matrix and with
|
|
47
|
+
* `GENERATOR_OUTPUT_ROOTS` by `lint_supported_tools_matrix`) and
|
|
48
|
+
* `USER_SCOPE_PATHS`. These cover the surfaces whose generators need a
|
|
49
|
+
* whole repository to run and so cannot be executed from inside a gate.
|
|
50
|
+
* The two are NOT interchangeable and the split is load-bearing: a
|
|
51
|
+
* declared root is a directory an emitter writes into, so a cell may
|
|
52
|
+
* refine it; an anchor is a whole tool's home and is matched exactly. See
|
|
53
|
+
* {@link anchorDirs} for what conflating them accepted.
|
|
54
|
+
*
|
|
55
|
+
* Exit codes: 0 every named path is emitted · 1 a cell names a path no emitter
|
|
56
|
+
* writes · 2 the document is missing, or its table is gone (a gate that read
|
|
57
|
+
* nothing has not passed).
|
|
58
|
+
*/
|
|
59
|
+
import * as fs from 'node:fs';
|
|
60
|
+
import * as os from 'node:os';
|
|
61
|
+
import * as path from 'node:path';
|
|
62
|
+
import process from 'node:process';
|
|
63
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
64
|
+
|
|
65
|
+
import { ADAPTER_REGISTRY } from './_lib/tool_adapter_registry.js';
|
|
66
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
67
|
+
import { splitMarkdownRow } from './_lib/md_table.js';
|
|
68
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
69
|
+
import { emitCursor, emitWindsurf } from '../install/emit_host_rules_cli.js';
|
|
70
|
+
import { USER_SCOPE_PATHS } from '../install/wizard-plan.js';
|
|
71
|
+
|
|
72
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
73
|
+
const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
74
|
+
|
|
75
|
+
export const GATE = 'check_host_format_column';
|
|
76
|
+
export const DOC_REL = path.join('docs', 'enforcement-by-host.md');
|
|
77
|
+
|
|
78
|
+
/** The header row that opens the table this gate reads. Matched exactly. */
|
|
79
|
+
export const TABLE_HEADER = '| Host | Compile-time rules | Lifecycle slots bound |';
|
|
80
|
+
|
|
81
|
+
const KNOWN_FLAGS: ReadonlySet<string> = new Set(['--self-test', '--root', '--quiet']);
|
|
82
|
+
|
|
83
|
+
export interface FormatCell {
|
|
84
|
+
/** The row's first cell, verbatim. */
|
|
85
|
+
host: string;
|
|
86
|
+
/** The compile-time cell, verbatim. */
|
|
87
|
+
cell: string;
|
|
88
|
+
/** Backtick-quoted tokens in the cell that look like paths. */
|
|
89
|
+
tokens: string[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Does a backticked token look like a path rather than prose?
|
|
94
|
+
*
|
|
95
|
+
* Deliberately permissive in one direction only: a token that is not a path is
|
|
96
|
+
* skipped, so a cell may carry `✅` or a word in backticks without being
|
|
97
|
+
* dragged into the comparison. A token that IS a path is always checked — the
|
|
98
|
+
* class this gate exists for.
|
|
99
|
+
*/
|
|
100
|
+
export function looksLikePath(token: string): boolean {
|
|
101
|
+
if (token === '') return false;
|
|
102
|
+
return token.includes('/') || token.startsWith('.') || token.endsWith('.md');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Read the host table's format column. Returns [] when the table is absent. */
|
|
106
|
+
export function parseFormatColumn(docText: string): FormatCell[] {
|
|
107
|
+
const lines = docText.split('\n');
|
|
108
|
+
const start = lines.findIndex((l) => l.trim() === TABLE_HEADER);
|
|
109
|
+
if (start === -1) return [];
|
|
110
|
+
const out: FormatCell[] = [];
|
|
111
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
112
|
+
const line = lines[i] ?? '';
|
|
113
|
+
if (!line.trim().startsWith('|')) break;
|
|
114
|
+
const cells = splitMarkdownRow(line);
|
|
115
|
+
const host = cells[0] ?? '';
|
|
116
|
+
// The separator row (`|---|---|---|`) is structure, not a row.
|
|
117
|
+
if (/^:?-{2,}:?$/.test(host)) continue;
|
|
118
|
+
const cell = cells[1] ?? '';
|
|
119
|
+
const tokens = [...cell.matchAll(/`([^`]+)`/g)]
|
|
120
|
+
.map((m) => m[1] ?? '')
|
|
121
|
+
.filter(looksLikePath);
|
|
122
|
+
out.push({ host, cell, tokens });
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Strip `~/`, collapse separators, drop leading and trailing slashes. */
|
|
128
|
+
export function normalizeSurface(p: string): string[] {
|
|
129
|
+
const cleaned = p
|
|
130
|
+
.trim()
|
|
131
|
+
.replace(/^~[/\\]/, '')
|
|
132
|
+
.replace(/\\/g, '/')
|
|
133
|
+
.replace(/^\/+/, '')
|
|
134
|
+
.replace(/\/+$/, '');
|
|
135
|
+
return cleaned.split('/').filter((s) => s !== '');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** One path segment, with `*` matching any run of non-separator characters. */
|
|
139
|
+
function segmentMatches(tokenSeg: string, surfaceSeg: string): boolean {
|
|
140
|
+
if (!tokenSeg.includes('*')) return tokenSeg === surfaceSeg;
|
|
141
|
+
const rx = new RegExp(
|
|
142
|
+
`^${tokenSeg.split('*').map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('[^/]*')}$`,
|
|
143
|
+
);
|
|
144
|
+
return rx.test(surfaceSeg);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Does a table token name the same surface as an emitted path?
|
|
149
|
+
*
|
|
150
|
+
* Three relations count, and each answers a real shape the column uses:
|
|
151
|
+
*
|
|
152
|
+
* - the token is the emitted path, segment for segment (`.clinerules`);
|
|
153
|
+
* - the token REFINES an emitted root, so the root is a prefix of it
|
|
154
|
+
* (`.cursor/rules/*.mdc` under the emitted root `.cursor/rules`), or the
|
|
155
|
+
* token is a root the emitter wrote a file beneath;
|
|
156
|
+
* - the token is the emitted path's tail, so a cell may name a surface by the
|
|
157
|
+
* filename a reader recognises (`copilot-instructions.md` for the emitted
|
|
158
|
+
* `.github/copilot-instructions.md`).
|
|
159
|
+
*
|
|
160
|
+
* The tail relation is the loosest of the three and is worth naming as such: it
|
|
161
|
+
* accepts a token that omits a directory. It does NOT loosen the case this gate
|
|
162
|
+
* was built for — `.cursorrules` is one segment, and no emitted path in this
|
|
163
|
+
* tree has a segment by that name, so it matches under none of the three.
|
|
164
|
+
*/
|
|
165
|
+
export function matchesSurface(token: string, surface: string, refineable = true): boolean {
|
|
166
|
+
const t = normalizeSurface(token);
|
|
167
|
+
const s = normalizeSurface(surface);
|
|
168
|
+
if (t.length === 0 || s.length === 0) return false;
|
|
169
|
+
const prefix = (a: string[], b: string[]): boolean =>
|
|
170
|
+
a.length <= b.length && a.every((seg, i) => segmentMatches(seg, b[i] ?? ''));
|
|
171
|
+
if (prefix(t, s)) return true;
|
|
172
|
+
if (!refineable) return false;
|
|
173
|
+
if (prefix(s, t)) return true;
|
|
174
|
+
// Tail relation: compare the token against the last |t| segments.
|
|
175
|
+
if (t.length < s.length) {
|
|
176
|
+
const tail = s.slice(s.length - t.length);
|
|
177
|
+
return t.every((seg, i) => segmentMatches(seg, tail[i] ?? ''));
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Run the install-time rule emitters into a throwaway tree and report what they
|
|
184
|
+
* wrote, repo-relative and posix-separated.
|
|
185
|
+
*
|
|
186
|
+
* This is the measured half of the oracle. The fixture is one rule file with
|
|
187
|
+
* the frontmatter a real rule carries, because the emitters read frontmatter to
|
|
188
|
+
* build their host-native forms and an empty file would exercise a path no
|
|
189
|
+
* install takes.
|
|
190
|
+
*/
|
|
191
|
+
export function measuredEmitterSurfaces(): string[] {
|
|
192
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'host-format-column-'));
|
|
193
|
+
try {
|
|
194
|
+
const rulesDir = path.join(tmp, 'rules');
|
|
195
|
+
const projectRoot = path.join(tmp, 'project');
|
|
196
|
+
fs.mkdirSync(rulesDir, { recursive: true });
|
|
197
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
198
|
+
fs.writeFileSync(
|
|
199
|
+
path.join(rulesDir, 'fixture-rule.md'),
|
|
200
|
+
[
|
|
201
|
+
'---',
|
|
202
|
+
'type: auto',
|
|
203
|
+
'description: Fixture rule, used only to measure emitter output paths.',
|
|
204
|
+
'triggers: [fixture]',
|
|
205
|
+
'---',
|
|
206
|
+
'# Fixture rule',
|
|
207
|
+
'',
|
|
208
|
+
'Body.',
|
|
209
|
+
'',
|
|
210
|
+
].join('\n'),
|
|
211
|
+
'utf-8',
|
|
212
|
+
);
|
|
213
|
+
emitCursor(rulesDir, projectRoot);
|
|
214
|
+
emitWindsurf(rulesDir, projectRoot);
|
|
215
|
+
|
|
216
|
+
const found: string[] = [];
|
|
217
|
+
const walk = (dir: string): void => {
|
|
218
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
219
|
+
const full = path.join(dir, ent.name);
|
|
220
|
+
if (ent.isDirectory()) walk(full);
|
|
221
|
+
else found.push(path.relative(projectRoot, full).split(path.sep).join('/'));
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
walk(projectRoot);
|
|
225
|
+
return found.sort();
|
|
226
|
+
} finally {
|
|
227
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The declared half of the oracle — tool roots the projection generators are
|
|
233
|
+
* already bound to. These are roots an emitter writes INTO, so a cell may
|
|
234
|
+
* legitimately refine one (`.cursor/rules` → `.cursor/rules/*.mdc`).
|
|
235
|
+
*/
|
|
236
|
+
export function declaredRoots(): string[] {
|
|
237
|
+
const out = new Set<string>();
|
|
238
|
+
for (const entry of ADAPTER_REGISTRY) {
|
|
239
|
+
for (const root of entry.roots) out.add(root);
|
|
240
|
+
}
|
|
241
|
+
return [...out].sort();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The installer's per-tool user-scope anchor directories.
|
|
246
|
+
*
|
|
247
|
+
* These are matched EXACTLY and are deliberately not refineable, which the
|
|
248
|
+
* self-test pins. An anchor is a whole tool's home (`~/.cursor/`), so treating
|
|
249
|
+
* it as a root anything may refine accepts every path beneath it — and the
|
|
250
|
+
* gate's own self-test caught exactly that: `.cursor/rules.mdc`, a plausible
|
|
251
|
+
* mistyping of the Cursor cell, passed on the strength of the `~/.cursor/`
|
|
252
|
+
* anchor while no emitter writes it. A cell may name an anchor (the Codex row
|
|
253
|
+
* names `~/.codex/`); it may not name something inside one and be believed.
|
|
254
|
+
*/
|
|
255
|
+
export function anchorDirs(): string[] {
|
|
256
|
+
return [...new Set(Object.values(USER_SCOPE_PATHS))].sort();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export interface Finding {
|
|
260
|
+
host: string;
|
|
261
|
+
token: string;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Every format-column token that no emitted surface accounts for. */
|
|
265
|
+
export function unemittedTokens(
|
|
266
|
+
cells: readonly FormatCell[],
|
|
267
|
+
roots: readonly string[],
|
|
268
|
+
anchors: readonly string[],
|
|
269
|
+
): Finding[] {
|
|
270
|
+
const findings: Finding[] = [];
|
|
271
|
+
for (const row of cells) {
|
|
272
|
+
for (const token of row.tokens) {
|
|
273
|
+
const backed =
|
|
274
|
+
roots.some((s) => matchesSurface(token, s)) ||
|
|
275
|
+
anchors.some((s) => matchesSurface(token, s, false));
|
|
276
|
+
if (!backed) findings.push({ host: row.host, token });
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return findings;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function _read(root: string, rel: string): string | null {
|
|
283
|
+
try {
|
|
284
|
+
return fs.readFileSync(path.join(root, rel), 'utf-8');
|
|
285
|
+
} catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function main(argv?: readonly string[]): number {
|
|
291
|
+
const args = argv ?? process.argv.slice(2);
|
|
292
|
+
// An unrecognised flag is refused rather than ignored: this gate runs in a
|
|
293
|
+
// required CI job, and a mistyped flag that still exits 0 hands back a
|
|
294
|
+
// green nobody earned.
|
|
295
|
+
const unknown = args.filter(
|
|
296
|
+
(a, i) => a.startsWith('-') && !KNOWN_FLAGS.has(a) && args[i - 1] !== '--root',
|
|
297
|
+
);
|
|
298
|
+
if (unknown.length > 0) {
|
|
299
|
+
process.stderr.write(
|
|
300
|
+
`${GATE}: unrecognised flag(s): ${unknown.join(', ')}\n` +
|
|
301
|
+
` known: ${[...KNOWN_FLAGS].join(', ')}\n`,
|
|
302
|
+
);
|
|
303
|
+
return 2;
|
|
304
|
+
}
|
|
305
|
+
if (args.includes('--self-test')) return selfTest();
|
|
306
|
+
// `--root` is validated rather than coalesced. Silently falling back to
|
|
307
|
+
// ROOT on a missing or option-shaped value means `--root --quiet` checks
|
|
308
|
+
// THIS repository while the caller believes it checked a fixture, and a
|
|
309
|
+
// fixture test written that way passes without ever reading the fixture.
|
|
310
|
+
// Repeats are refused for the same reason: two values and one winner is a
|
|
311
|
+
// caller who does not know which root was read.
|
|
312
|
+
const rootFlags = args.filter((a) => a === '--root');
|
|
313
|
+
if (rootFlags.length > 1) {
|
|
314
|
+
process.stderr.write(`${GATE}: \`--root\` given ${String(rootFlags.length)} times; pass it once.\n`);
|
|
315
|
+
return 2;
|
|
316
|
+
}
|
|
317
|
+
const rootIdx = args.indexOf('--root');
|
|
318
|
+
if (rootIdx !== -1) {
|
|
319
|
+
const v = args[rootIdx + 1];
|
|
320
|
+
if (v === undefined || v.startsWith('-')) {
|
|
321
|
+
process.stderr.write(
|
|
322
|
+
`${GATE}: \`--root\` needs a directory` +
|
|
323
|
+
(v === undefined ? '' : `, got \`${v}\``) +
|
|
324
|
+
'.\n',
|
|
325
|
+
);
|
|
326
|
+
return 2;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const positional = args.filter((a, i) => !a.startsWith('-') && args[i - 1] !== '--root');
|
|
330
|
+
if (positional.length > 0) {
|
|
331
|
+
process.stderr.write(`${GATE}: unexpected argument(s): ${positional.join(', ')}\n`);
|
|
332
|
+
return 2;
|
|
333
|
+
}
|
|
334
|
+
const root = rootIdx === -1 ? ROOT : (args[rootIdx + 1] as string);
|
|
335
|
+
const quiet = args.includes('--quiet');
|
|
336
|
+
|
|
337
|
+
const docText = _read(root, DOC_REL);
|
|
338
|
+
if (docText === null) {
|
|
339
|
+
process.stderr.write(`❌ ${GATE}: ${DOC_REL} not found under ${root}\n`);
|
|
340
|
+
return 2;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const cells = parseFormatColumn(docText);
|
|
344
|
+
|
|
345
|
+
// The scope assertion runs BEFORE the verdict. A document whose table
|
|
346
|
+
// header moved or whose rows were deleted yields zero cells, and a gate
|
|
347
|
+
// that read nothing must fail loudly rather than print a green over an
|
|
348
|
+
// empty corpus.
|
|
349
|
+
try {
|
|
350
|
+
reportScanned({
|
|
351
|
+
gate: GATE,
|
|
352
|
+
scanned: cells.length,
|
|
353
|
+
units: 'format-column cell(s)',
|
|
354
|
+
roots: [DOC_REL],
|
|
355
|
+
});
|
|
356
|
+
} catch (exc) {
|
|
357
|
+
if (exc instanceof DeadScopeError) {
|
|
358
|
+
process.stderr.write(
|
|
359
|
+
`❌ ${exc.message}\n` +
|
|
360
|
+
` The table is found by its header line, matched exactly:\n` +
|
|
361
|
+
` ${TABLE_HEADER}\n`,
|
|
362
|
+
);
|
|
363
|
+
return 2;
|
|
364
|
+
}
|
|
365
|
+
throw exc;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const measured = measuredEmitterSurfaces();
|
|
369
|
+
const roots = [...new Set([...measured, ...declaredRoots()])];
|
|
370
|
+
const anchors = anchorDirs();
|
|
371
|
+
|
|
372
|
+
const findings = unemittedTokens(cells, roots, anchors);
|
|
373
|
+
|
|
374
|
+
if (!quiet) {
|
|
375
|
+
process.stdout.write(
|
|
376
|
+
`${GATE}: ${String(measured.length)} measured emitter path(s), ` +
|
|
377
|
+
`${String(roots.length)} emitted root(s), ` +
|
|
378
|
+
`${String(anchors.length)} user-scope anchor(s) (exact match only)\n`,
|
|
379
|
+
);
|
|
380
|
+
for (const m of measured) process.stdout.write(` measured ${m}\n`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (findings.length > 0) {
|
|
384
|
+
for (const f of findings) {
|
|
385
|
+
process.stdout.write(
|
|
386
|
+
`❌ ${GATE}: ${DOC_REL} § the ${f.host} row names \`${f.token}\`, ` +
|
|
387
|
+
'which is neither a measured emitter output nor a declared ' +
|
|
388
|
+
'emitted root.\n',
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
process.stdout.write(
|
|
392
|
+
`\n${String(findings.length)} finding(s). The format column describes generated ` +
|
|
393
|
+
'output, so the correction belongs in the cell — name the path an emitter ' +
|
|
394
|
+
'really writes. Emitted roots this gate knows about:\n' +
|
|
395
|
+
roots
|
|
396
|
+
.slice()
|
|
397
|
+
.sort()
|
|
398
|
+
.map((s) => ` ${s}\n`)
|
|
399
|
+
.join('') +
|
|
400
|
+
'If a NEW emitter was added, it belongs in `ADAPTER_REGISTRY` (or in the ' +
|
|
401
|
+
'measured pair) in the same change — a gate that cannot see an emitter ' +
|
|
402
|
+
'reports a true cell as drift, which is how a gate gets disabled.\n',
|
|
403
|
+
);
|
|
404
|
+
return 1;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// The claim is deliberately weaker than "an emitter wrote this path". Only
|
|
408
|
+
// the MEASURED half was observed being written; the DECLARED half is a root
|
|
409
|
+
// read out of `ADAPTER_REGISTRY`, which is the projection's source of truth
|
|
410
|
+
// but is not an observation this run took. An independent review refused
|
|
411
|
+
// the earlier wording for overstating exactly that gap, and a gate whose
|
|
412
|
+
// green line claims more than its oracle checked is the failure this file
|
|
413
|
+
// was written to stop, one level up.
|
|
414
|
+
process.stdout.write(
|
|
415
|
+
`✅ ${GATE}: every path named in ${String(cells.length)} format-column cell(s) of ` +
|
|
416
|
+
`${DOC_REL} resolves to a measured emitter output or to a root declared in ` +
|
|
417
|
+
'`ADAPTER_REGISTRY`.\n',
|
|
418
|
+
);
|
|
419
|
+
return 0;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* One rejecting case per way the column and the emitters can part company.
|
|
424
|
+
*
|
|
425
|
+
* The first is the historical defect by name: planting `.cursorrules` back into
|
|
426
|
+
* the Cursor cell must red the gate. The empty-root case is the scope
|
|
427
|
+
* assertion's own — a document with no table must fail rather than pass over an
|
|
428
|
+
* empty corpus.
|
|
429
|
+
*/
|
|
430
|
+
function selfTest(): number {
|
|
431
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'host-format-column-st-'));
|
|
432
|
+
const docText = _read(ROOT, DOC_REL) ?? '';
|
|
433
|
+
const plant = (name: string, mutate: (doc: string) => string): string => {
|
|
434
|
+
const dir = path.join(tmp, name);
|
|
435
|
+
fs.mkdirSync(path.join(dir, path.dirname(DOC_REL)), { recursive: true });
|
|
436
|
+
fs.writeFileSync(path.join(dir, DOC_REL), mutate(docText), 'utf-8');
|
|
437
|
+
return dir;
|
|
438
|
+
};
|
|
439
|
+
const run = (root: string): number =>
|
|
440
|
+
runGateCli(ROOT, `src/scripts/${GATE}.ts`, ['--root', root, '--quiet'], root);
|
|
441
|
+
// Argv cases run against a planted-GOOD root, so the only thing that can
|
|
442
|
+
// make them non-zero is the argument shape. An argv guard tested against a
|
|
443
|
+
// root that would fail anyway proves nothing about the guard.
|
|
444
|
+
const runArgs = (args: readonly string[]): number =>
|
|
445
|
+
runGateCli(ROOT, `src/scripts/${GATE}.ts`, args, ROOT);
|
|
446
|
+
|
|
447
|
+
try {
|
|
448
|
+
return runSelfTest({
|
|
449
|
+
gate: GATE,
|
|
450
|
+
minCases: 9,
|
|
451
|
+
minRejectCases: 8,
|
|
452
|
+
cases: [
|
|
453
|
+
{
|
|
454
|
+
name: 'the historical defect — `.cursorrules` planted back into the Cursor cell',
|
|
455
|
+
expect: 'reject',
|
|
456
|
+
run: () =>
|
|
457
|
+
run(
|
|
458
|
+
plant('cursorrules', (d) =>
|
|
459
|
+
d.replace(
|
|
460
|
+
'| Cursor | ✅ `.cursor/rules/*.mdc` | 5 |',
|
|
461
|
+
'| Cursor | ✅ `.cursorrules` | 5 |',
|
|
462
|
+
),
|
|
463
|
+
),
|
|
464
|
+
),
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
// The row is replaced whole, never just the token: the same
|
|
468
|
+
// token appears in the prose paragraph above the table,
|
|
469
|
+
// which this gate does not scan, and `String.replace` takes
|
|
470
|
+
// the FIRST occurrence — so a token-level fixture silently
|
|
471
|
+
// mutated the prose and asserted nothing. Caught by this
|
|
472
|
+
// suite reporting the case as not behaving.
|
|
473
|
+
name: 'a plausible near-miss — `.cursor/rules.mdc` — is rejected',
|
|
474
|
+
expect: 'reject',
|
|
475
|
+
run: () =>
|
|
476
|
+
run(
|
|
477
|
+
plant('nearmiss', (d) =>
|
|
478
|
+
d.replace(
|
|
479
|
+
'| Cursor | ✅ `.cursor/rules/*.mdc` | 5 |',
|
|
480
|
+
'| Cursor | ✅ `.cursor/rules.mdc` | 5 |',
|
|
481
|
+
),
|
|
482
|
+
),
|
|
483
|
+
),
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
name: 'an invented surface on a correct neighbouring row is rejected',
|
|
487
|
+
expect: 'reject',
|
|
488
|
+
run: () =>
|
|
489
|
+
run(plant('invented', (d) => d.replace('| Cline | ✅ `.clinerules` | 5 |', '| Cline | ✅ `.clinereles` | 5 |'))),
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: 'a document with no host table is rejected, not passed over an empty corpus',
|
|
493
|
+
expect: 'reject',
|
|
494
|
+
run: () => run(plant('empty', (d) => d.replace(TABLE_HEADER, '| Host | Other |'))),
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
name: 'the committed table passes',
|
|
498
|
+
expect: 'accept',
|
|
499
|
+
run: () => run(plant('good', (d) => d)),
|
|
500
|
+
},
|
|
501
|
+
// The three argv shapes an independent review found accepted on
|
|
502
|
+
// 2026-09-29. Each one silently read THIS repository while the
|
|
503
|
+
// caller believed it had named a root — a fixture test written
|
|
504
|
+
// that way passes without ever opening the fixture, which is the
|
|
505
|
+
// failure mode a gate's own self-test exists to make impossible.
|
|
506
|
+
// Both shapes below are constructed so the COALESCING code
|
|
507
|
+
// would have exited 0: a trailing `--root` and a repeated
|
|
508
|
+
// `--root ROOT` both fall back to ROOT, which passes. Pointing
|
|
509
|
+
// them at a root that fails anyway would have made the cases
|
|
510
|
+
// reject on the unfixed code too — a test that cannot fail for
|
|
511
|
+
// the reason it names.
|
|
512
|
+
{
|
|
513
|
+
name: 'a trailing `--root` with no value is refused, not coalesced to ROOT',
|
|
514
|
+
expect: 'reject',
|
|
515
|
+
run: () => runArgs(['--quiet', '--root']),
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: '`--root` given twice is refused rather than silently picking one',
|
|
519
|
+
expect: 'reject',
|
|
520
|
+
run: () => runArgs(['--root', ROOT, '--root', ROOT, '--quiet']),
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: 'an unexpected positional argument is refused',
|
|
524
|
+
expect: 'reject',
|
|
525
|
+
run: () => runArgs(['stray', '--quiet']),
|
|
526
|
+
},
|
|
527
|
+
// Round 3 of the review asked for this shape by name, and it is
|
|
528
|
+
// carried with its limitation stated: it does NOT discriminate.
|
|
529
|
+
// The coalescing code set `root = '--quiet'`, found no document
|
|
530
|
+
// under it, and also exited 2 — so this case pins the branch's
|
|
531
|
+
// behavior and documents the motivating shape, while the three
|
|
532
|
+
// cases above are the ones that would have caught the defect.
|
|
533
|
+
// Labelled rather than quietly counted, because a self-test
|
|
534
|
+
// suite whose cases are not all discriminating should say which.
|
|
535
|
+
{
|
|
536
|
+
name: '`--root` with an option-shaped value is refused (pins the shape; does not discriminate)',
|
|
537
|
+
expect: 'reject',
|
|
538
|
+
run: () => runArgs(['--root', '--quiet']),
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
});
|
|
542
|
+
} finally {
|
|
543
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function _isCliEntry(): boolean {
|
|
548
|
+
if (process.argv[1] === undefined) return false;
|
|
549
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
550
|
+
try {
|
|
551
|
+
return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
552
|
+
} catch {
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (_isCliEntry()) {
|
|
558
|
+
process.exit(main());
|
|
559
|
+
}
|