@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,228 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Every in-body `${x}` on an artifact that declares `inputs:` is backed by a
|
|
4
|
+
* declaration.
|
|
5
|
+
*
|
|
6
|
+
* road-to-an-invocation-contract-that-reaches-the-wire 2.2.
|
|
7
|
+
*
|
|
8
|
+
* SCOPED TO DECLARING ARTIFACTS, ON PURPOSE
|
|
9
|
+
*
|
|
10
|
+
* An artifact with no `inputs:` block is not checked at all. That is what lets
|
|
11
|
+
* this arrive with zero findings over a corpus where nothing declares anything
|
|
12
|
+
* yet, and grow only with adoption — a check that fired on every artifact would
|
|
13
|
+
* have to be introduced together with a migration nobody asked for, which is
|
|
14
|
+
* exactly what the optional block was designed to avoid.
|
|
15
|
+
*
|
|
16
|
+
* THE COUNTING UNIT IS THE CENSUS'S, IMPORTED
|
|
17
|
+
*
|
|
18
|
+
* A reference counts when it appears in PROSE — outside fenced code blocks,
|
|
19
|
+
* indented blocks and inline code spans. `proseOnly` is imported from
|
|
20
|
+
* `report_invocation_surface.ts` rather than restated, because two copies of
|
|
21
|
+
* that definition would drift and the whole point of this phase is that the
|
|
22
|
+
* declaration and what depends on it cannot disagree.
|
|
23
|
+
*
|
|
24
|
+
* The consequence is stated rather than hidden: a `${target}` inside a fenced
|
|
25
|
+
* usage example is NOT checked. That is the conservative direction. A skill
|
|
26
|
+
* teaching Terraform has `${local.x}` in a fence and would otherwise be
|
|
27
|
+
* reported against a declaration it never claimed to satisfy — a false positive
|
|
28
|
+
* on working content, which is the failure that makes a young gate get
|
|
29
|
+
* disabled. When adoption makes in-fence usage examples common, widening the
|
|
30
|
+
* unit is a deliberate change with its own diff.
|
|
31
|
+
*
|
|
32
|
+
* Exit codes: 0 every reference backed · 1 an unbacked reference · 2 the corpus
|
|
33
|
+
* could not be read.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import fs from 'node:fs';
|
|
37
|
+
import os from 'node:os';
|
|
38
|
+
import path from 'node:path';
|
|
39
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
40
|
+
|
|
41
|
+
import * as yaml from 'js-yaml';
|
|
42
|
+
|
|
43
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
44
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
45
|
+
import { assertScanned, reportScanned } from './_lib/scan_scope.js';
|
|
46
|
+
import { proseOnly } from './report_invocation_surface.js';
|
|
47
|
+
|
|
48
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
49
|
+
const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
50
|
+
|
|
51
|
+
export const GATE = 'check_input_references';
|
|
52
|
+
|
|
53
|
+
/** The reference form this checks. Only the plurality syntax is a reference. */
|
|
54
|
+
const REFERENCE_RE = /\$\{([a-z][a-z0-9_]*)\}/g;
|
|
55
|
+
|
|
56
|
+
export interface Unbacked {
|
|
57
|
+
readonly file: string;
|
|
58
|
+
readonly name: string;
|
|
59
|
+
readonly declared: readonly string[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Declared input names, or `null` when the artifact declares no block at all. */
|
|
63
|
+
export function declaredInputs(text: string): string[] | null {
|
|
64
|
+
const m = /^---\n([\s\S]*?)\n---/.exec(text);
|
|
65
|
+
if (m === null) return null;
|
|
66
|
+
let fm: unknown;
|
|
67
|
+
try {
|
|
68
|
+
fm = yaml.load(m[1]!);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (fm === null || typeof fm !== 'object') return null;
|
|
73
|
+
const inputs = (fm as Record<string, unknown>)['inputs'];
|
|
74
|
+
if (!Array.isArray(inputs)) return null;
|
|
75
|
+
const names: string[] = [];
|
|
76
|
+
for (const item of inputs) {
|
|
77
|
+
if (item === null || typeof item !== 'object') continue;
|
|
78
|
+
const name = (item as Record<string, unknown>)['name'];
|
|
79
|
+
if (typeof name === 'string') names.push(name);
|
|
80
|
+
}
|
|
81
|
+
return names;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Prose `${x}` references with no matching declaration.
|
|
86
|
+
*
|
|
87
|
+
* Returns `[]` for an artifact that declares no block — not because it has no
|
|
88
|
+
* references, but because it is out of scope.
|
|
89
|
+
*/
|
|
90
|
+
export function unbackedReferences(text: string, file = '<data>'): Unbacked[] {
|
|
91
|
+
const declared = declaredInputs(text);
|
|
92
|
+
if (declared === null) return [];
|
|
93
|
+
const seen = new Set<string>();
|
|
94
|
+
const out: Unbacked[] = [];
|
|
95
|
+
for (const m of proseOnly(text).matchAll(REFERENCE_RE)) {
|
|
96
|
+
const name = m[1]!;
|
|
97
|
+
if (declared.includes(name) || seen.has(name)) continue;
|
|
98
|
+
seen.add(name);
|
|
99
|
+
out.push({ file, name, declared });
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function walk(dir: string, match: (n: string) => boolean, out: string[] = []): string[] {
|
|
105
|
+
if (!fs.existsSync(dir)) return out;
|
|
106
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
107
|
+
const p = path.join(dir, e.name);
|
|
108
|
+
if (e.isDirectory()) walk(p, match, out);
|
|
109
|
+
else if (match(e.name)) out.push(p);
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function scan(root: string): { findings: Unbacked[]; scanned: number; declaring: number } {
|
|
115
|
+
const files = [
|
|
116
|
+
...walk(path.join(root, 'dist', 'agent-src', 'commands'), (n) => n.endsWith('.md')),
|
|
117
|
+
...walk(path.join(root, 'src', 'skills'), (n) => n === 'SKILL.md'),
|
|
118
|
+
].sort();
|
|
119
|
+
|
|
120
|
+
const findings: Unbacked[] = [];
|
|
121
|
+
let declaring = 0;
|
|
122
|
+
for (const f of files) {
|
|
123
|
+
const text = fs.readFileSync(f, 'utf8');
|
|
124
|
+
if (declaredInputs(text) !== null) declaring += 1;
|
|
125
|
+
findings.push(...unbackedReferences(text, path.relative(root, f)));
|
|
126
|
+
}
|
|
127
|
+
return { findings, scanned: files.length, declaring };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function main(argv: readonly string[]): number {
|
|
131
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
132
|
+
const rootIdx = argv.indexOf('--root');
|
|
133
|
+
const root = rootIdx === -1 ? ROOT : (argv[rootIdx + 1] ?? ROOT);
|
|
134
|
+
|
|
135
|
+
const { findings, scanned, declaring } = scan(root);
|
|
136
|
+
const ledger = new GateLedger(GATE);
|
|
137
|
+
ledger.plan(findings.map((f) => `${f.file}:${f.name}`));
|
|
138
|
+
for (const f of findings) {
|
|
139
|
+
ledger.fail(`${f.file}:${f.name}`, `\`\${${f.name}}\` is not declared`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// A gate that read nothing has not passed. This fires BEFORE the verdict,
|
|
143
|
+
// because certifying against an empty corpus is the false green the coverage
|
|
144
|
+
// manifest exists to refuse — named by the provider-diverse ratification
|
|
145
|
+
// review as one condition that would have flipped its verdict.
|
|
146
|
+
assertScanned({ gate: GATE, scanned: scanned, units: 'artifact(s)', roots: ['dist/agent-src/commands', 'src/skills'] });
|
|
147
|
+
|
|
148
|
+
reportScanned({
|
|
149
|
+
gate: GATE,
|
|
150
|
+
scanned,
|
|
151
|
+
units: 'artifact(s)',
|
|
152
|
+
roots: ['dist/agent-src/commands', 'src/skills'],
|
|
153
|
+
});
|
|
154
|
+
ledger.report();
|
|
155
|
+
|
|
156
|
+
if (findings.length > 0) {
|
|
157
|
+
for (const f of findings) {
|
|
158
|
+
process.stdout.write(
|
|
159
|
+
`❌ ${GATE}: ${f.file} references \`\${${f.name}}\` with no \`inputs.${f.name}\` ` +
|
|
160
|
+
`(declared: ${f.declared.length > 0 ? f.declared.join(', ') : 'none'}).\n`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
process.stdout.write(
|
|
164
|
+
'\nAdd the declaration, or drop the reference. Only artifacts that declare ' +
|
|
165
|
+
'`inputs:` at all are checked, so this never asks an artifact to start ' +
|
|
166
|
+
'declaring — it asks a declaration to be complete.\n',
|
|
167
|
+
);
|
|
168
|
+
return 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
process.stdout.write(
|
|
172
|
+
`✅ ${GATE}: every in-body reference is backed ` +
|
|
173
|
+
`(${String(declaring)} of ${String(scanned)} artifact(s) declare \`inputs:\`).\n`,
|
|
174
|
+
);
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A self-test is what proves a gate DISCRIMINATES. An enforced scan floor only
|
|
180
|
+
* proves it read something; the verdict has to move.
|
|
181
|
+
*/
|
|
182
|
+
function selfTest(): number {
|
|
183
|
+
const plant = (name: string, body: string): string => {
|
|
184
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `input-refs-${name}-`));
|
|
185
|
+
const skills = path.join(dir, 'src', 'skills', 'probe');
|
|
186
|
+
fs.mkdirSync(skills, { recursive: true });
|
|
187
|
+
fs.writeFileSync(path.join(skills, 'SKILL.md'), body, 'utf-8');
|
|
188
|
+
return dir;
|
|
189
|
+
};
|
|
190
|
+
const declaring = (ref: string): string =>
|
|
191
|
+
`---\nname: probe\ninputs:\n - name: a\n type: string\n---\n\nUses ${ref} here.\n`;
|
|
192
|
+
|
|
193
|
+
const run = (root: string): number =>
|
|
194
|
+
runGateCli(ROOT, path.join('src', 'scripts', 'check_input_references.ts'), ['--root', root], ROOT);
|
|
195
|
+
|
|
196
|
+
return runSelfTest({
|
|
197
|
+
gate: GATE,
|
|
198
|
+
minCases: 4,
|
|
199
|
+
minRejectCases: 2,
|
|
200
|
+
cases: [
|
|
201
|
+
{
|
|
202
|
+
name: 'an empty corpus is refused, not certified green',
|
|
203
|
+
expect: 'reject',
|
|
204
|
+
run: () => run(fs.mkdtempSync(path.join(os.tmpdir(), 'input-refs-empty-'))),
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
name: 'a reference the declaration backs passes',
|
|
208
|
+
expect: 'accept',
|
|
209
|
+
run: () => run(plant('backed', declaring('${a}'))),
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
name: 'a reference nothing declares fails',
|
|
213
|
+
expect: 'reject',
|
|
214
|
+
run: () => run(plant('unbacked', declaring('${b}'))),
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: 'an artifact with no declaration is out of scope, however it references',
|
|
218
|
+
expect: 'accept',
|
|
219
|
+
run: () =>
|
|
220
|
+
run(plant('noblock', '---\nname: probe\n---\n\nUses ${anything} here.\n')),
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
227
|
+
process.exit(main(process.argv.slice(2)));
|
|
228
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* What the MCP server reads from an `inputs:` block equals what a real YAML
|
|
4
|
+
* parser reads from it.
|
|
5
|
+
*
|
|
6
|
+
* road-to-an-invocation-contract-that-reaches-the-wire — added after review.
|
|
7
|
+
*
|
|
8
|
+
* WHY THIS GATE EXISTS
|
|
9
|
+
*
|
|
10
|
+
* The server's `_parse_inputs` is a hand-rolled reader of a YAML subset,
|
|
11
|
+
* because the MCP server is stdlib-only and bundled and must not grow a YAML
|
|
12
|
+
* dependency to read one optional block. A hand-rolled reader of a format it
|
|
13
|
+
* does not fully implement has exactly one dangerous failure mode: reading
|
|
14
|
+
* something DIFFERENT from what the author wrote, silently. A host is then told
|
|
15
|
+
* about an argument that does not exist, or not told about one that does — and
|
|
16
|
+
* the schema validates either way, because the schema checks the YAML, not the
|
|
17
|
+
* reader.
|
|
18
|
+
*
|
|
19
|
+
* An independent review found that failure live: the reader's key scan ran at
|
|
20
|
+
* any depth, so a `default:` mapping whose first child was `name:` overwrote
|
|
21
|
+
* the parameter's own name. It also silently misread `required: True`, the
|
|
22
|
+
* flow form, a comment at column zero, and a block scalar. Every one of those
|
|
23
|
+
* is schema-valid.
|
|
24
|
+
*
|
|
25
|
+
* So the reader now DECLINES what it cannot model, and this gate makes every
|
|
26
|
+
* decline and every divergence a build failure with a named remedy. The
|
|
27
|
+
* contract is: write the block form, or the build tells you. That is strictly
|
|
28
|
+
* better than a reader that is clever and occasionally wrong, and it is why the
|
|
29
|
+
* reader is allowed to stay stdlib-only.
|
|
30
|
+
*
|
|
31
|
+
* Exit codes: 0 parity holds · 1 a divergence · 2 the corpus could not be read.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import fs from 'node:fs';
|
|
35
|
+
import os from 'node:os';
|
|
36
|
+
import path from 'node:path';
|
|
37
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
38
|
+
|
|
39
|
+
import * as yaml from 'js-yaml';
|
|
40
|
+
|
|
41
|
+
import { GateLedger } from './_lib/gate_ledger.js';
|
|
42
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
43
|
+
import { assertScanned, reportScanned } from './_lib/scan_scope.js';
|
|
44
|
+
import { _frontmatter_text, _parse_inputs, type PromptInput } from './mcp_server/prompts.js';
|
|
45
|
+
|
|
46
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
47
|
+
const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
48
|
+
|
|
49
|
+
export const GATE = 'check_inputs_parity';
|
|
50
|
+
|
|
51
|
+
/** The same reduction `_parse_inputs` produces, taken from a real YAML parse. */
|
|
52
|
+
export function yamlInputs(fmText: string): PromptInput[] | null {
|
|
53
|
+
let doc: unknown;
|
|
54
|
+
try {
|
|
55
|
+
doc = yaml.load(fmText);
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
if (doc === null || typeof doc !== 'object') return null;
|
|
60
|
+
const raw = (doc as Record<string, unknown>)['inputs'];
|
|
61
|
+
if (raw === undefined) return null;
|
|
62
|
+
if (!Array.isArray(raw)) return [];
|
|
63
|
+
const out: PromptInput[] = [];
|
|
64
|
+
for (const item of raw) {
|
|
65
|
+
if (item === null || typeof item !== 'object') continue;
|
|
66
|
+
const r = item as Record<string, unknown>;
|
|
67
|
+
if (typeof r['name'] !== 'string') continue;
|
|
68
|
+
out.push({
|
|
69
|
+
name: r['name'],
|
|
70
|
+
description: typeof r['description'] === 'string' ? r['description'] : '',
|
|
71
|
+
required: r['required'] === true,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface Divergence {
|
|
78
|
+
readonly file: string;
|
|
79
|
+
readonly server: PromptInput[];
|
|
80
|
+
readonly yaml: PromptInput[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const same = (a: readonly PromptInput[], b: readonly PromptInput[]): boolean =>
|
|
84
|
+
a.length === b.length &&
|
|
85
|
+
a.every(
|
|
86
|
+
(x, i) =>
|
|
87
|
+
x.name === b[i]!.name &&
|
|
88
|
+
x.required === b[i]!.required &&
|
|
89
|
+
x.description === b[i]!.description,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
/** Compare both readers over one document. `null` when it declares no block. */
|
|
93
|
+
export function compare(text: string, file: string): Divergence | null {
|
|
94
|
+
const fm = _frontmatter_text(text);
|
|
95
|
+
if (fm === '') return null;
|
|
96
|
+
const expected = yamlInputs(fm);
|
|
97
|
+
if (expected === null) return null;
|
|
98
|
+
const actual = _parse_inputs(fm);
|
|
99
|
+
return same(actual, expected) ? null : { file, server: actual, yaml: expected };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function walk(dir: string, match: (n: string) => boolean, out: string[] = []): string[] {
|
|
103
|
+
if (!fs.existsSync(dir)) return out;
|
|
104
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
105
|
+
const p = path.join(dir, e.name);
|
|
106
|
+
if (e.isDirectory()) walk(p, match, out);
|
|
107
|
+
else if (match(e.name)) out.push(p);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function scan(root: string): { findings: Divergence[]; scanned: number } {
|
|
113
|
+
const files = [
|
|
114
|
+
...walk(path.join(root, 'src', 'domains'), (n) => n === 'command.md'),
|
|
115
|
+
...walk(path.join(root, 'src', 'skills'), (n) => n === 'SKILL.md'),
|
|
116
|
+
...walk(path.join(root, 'dist', 'agent-src', 'commands'), (n) => n.endsWith('.md')),
|
|
117
|
+
].sort();
|
|
118
|
+
|
|
119
|
+
const findings: Divergence[] = [];
|
|
120
|
+
for (const f of files) {
|
|
121
|
+
const d = compare(fs.readFileSync(f, 'utf8'), path.relative(root, f));
|
|
122
|
+
if (d !== null) findings.push(d);
|
|
123
|
+
}
|
|
124
|
+
return { findings, scanned: files.length };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function main(argv: readonly string[]): number {
|
|
128
|
+
if (argv.includes('--self-test')) return selfTest();
|
|
129
|
+
const rootIdx = argv.indexOf('--root');
|
|
130
|
+
const root = rootIdx === -1 ? ROOT : (argv[rootIdx + 1] ?? ROOT);
|
|
131
|
+
|
|
132
|
+
const { findings, scanned } = scan(root);
|
|
133
|
+
const ledger = new GateLedger(GATE);
|
|
134
|
+
ledger.plan(findings.map((f) => f.file));
|
|
135
|
+
for (const f of findings) {
|
|
136
|
+
ledger.fail(f.file, `server read ${String(f.server.length)}, YAML read ${String(f.yaml.length)}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// A gate that read nothing has not passed. This fires BEFORE the verdict,
|
|
140
|
+
// because certifying against an empty corpus is the false green the coverage
|
|
141
|
+
// manifest exists to refuse — named by the provider-diverse ratification
|
|
142
|
+
// review as one condition that would have flipped its verdict.
|
|
143
|
+
assertScanned({ gate: GATE, scanned: scanned, units: 'artifact(s)', roots: ['src/domains', 'src/skills', 'dist/agent-src/commands'] });
|
|
144
|
+
|
|
145
|
+
reportScanned({
|
|
146
|
+
gate: GATE,
|
|
147
|
+
scanned,
|
|
148
|
+
units: 'artifact(s)',
|
|
149
|
+
roots: ['src/domains', 'src/skills', 'dist/agent-src/commands'],
|
|
150
|
+
});
|
|
151
|
+
ledger.report();
|
|
152
|
+
|
|
153
|
+
if (findings.length > 0) {
|
|
154
|
+
for (const f of findings) {
|
|
155
|
+
process.stdout.write(
|
|
156
|
+
`❌ ${GATE}: ${f.file} — the MCP reader and YAML disagree about \`inputs:\`.\n` +
|
|
157
|
+
` server: ${JSON.stringify(f.server)}\n` +
|
|
158
|
+
` yaml: ${JSON.stringify(f.yaml)}\n`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
process.stdout.write(
|
|
162
|
+
'\nThe server reads one shape, deliberately — a block sequence of `- name:` items ' +
|
|
163
|
+
'with scalar values on their own lines. Rewrite the declaration in that shape. ' +
|
|
164
|
+
'The flow form, a block scalar and a nested mapping under an item key are ' +
|
|
165
|
+
'refused rather than guessed at, and this gate is how the refusal is visible ' +
|
|
166
|
+
'instead of becoming a wrong argument on the wire.\n',
|
|
167
|
+
);
|
|
168
|
+
return 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
process.stdout.write(
|
|
172
|
+
`✅ ${GATE}: the MCP reader and YAML agree on every declared \`inputs:\` block.\n`,
|
|
173
|
+
);
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* One rejecting case per way the reader and YAML can part company, plus the
|
|
179
|
+
* agreeing case — because a suite that only proves passes proves nothing.
|
|
180
|
+
*/
|
|
181
|
+
function selfTest(): number {
|
|
182
|
+
const plant = (name: string, fm: string): string => {
|
|
183
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `inputs-parity-${name}-`));
|
|
184
|
+
const skills = path.join(dir, 'src', 'skills', 'probe');
|
|
185
|
+
fs.mkdirSync(skills, { recursive: true });
|
|
186
|
+
fs.writeFileSync(path.join(skills, 'SKILL.md'), `---\nname: probe\n${fm}---\n\nbody\n`, 'utf-8');
|
|
187
|
+
return dir;
|
|
188
|
+
};
|
|
189
|
+
const run = (root: string): number =>
|
|
190
|
+
runGateCli(ROOT, path.join('src', 'scripts', 'check_inputs_parity.ts'), ['--root', root], ROOT);
|
|
191
|
+
|
|
192
|
+
return runSelfTest({
|
|
193
|
+
gate: GATE,
|
|
194
|
+
minCases: 6,
|
|
195
|
+
minRejectCases: 5,
|
|
196
|
+
cases: [
|
|
197
|
+
{
|
|
198
|
+
name: 'an empty corpus is refused, not certified green',
|
|
199
|
+
expect: 'reject',
|
|
200
|
+
run: () => run(fs.mkdtempSync(path.join(os.tmpdir(), 'inputs-parity-empty-'))),
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'the supported block form agrees',
|
|
204
|
+
expect: 'accept',
|
|
205
|
+
run: () => run(plant('ok', 'inputs:\n - name: a\n type: string\n required: true\n')),
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'the flow form is a divergence',
|
|
209
|
+
expect: 'reject',
|
|
210
|
+
run: () => run(plant('flow', 'inputs: [{name: a, type: string}]\n')),
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: 'a nested mapping under an item key is a divergence',
|
|
214
|
+
expect: 'reject',
|
|
215
|
+
run: () =>
|
|
216
|
+
run(plant('nested', 'inputs:\n - name: opts\n type: string\n default:\n name: fallback\n')),
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'a block scalar is a divergence',
|
|
220
|
+
expect: 'reject',
|
|
221
|
+
run: () =>
|
|
222
|
+
run(plant('scalar', 'inputs:\n - name: a\n type: string\n description: >\n long\n')),
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'a dash on its own line is a divergence',
|
|
226
|
+
expect: 'reject',
|
|
227
|
+
run: () => run(plant('bareDash', 'inputs:\n -\n name: a\n type: string\n')),
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
234
|
+
process.exit(main(process.argv.slice(2)));
|
|
235
|
+
}
|
|
@@ -30,10 +30,14 @@
|
|
|
30
30
|
*
|
|
31
31
|
* Gated: a diff touching a kernel rule under `src/rules/` (the nine of
|
|
32
32
|
* `_lib/kernel_rules.ts`), a governance hook (`src/scripts/hooks/block_*.ts`),
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* the
|
|
36
|
-
*
|
|
33
|
+
* hook plumbing — the YAML sources `hook_manifest.yaml` and
|
|
34
|
+
* `host_lowering.yaml`, their compiled siblings `hook_manifest.json` and
|
|
35
|
+
* `host_lowering.json`, the dispatcher `hooks/dispatch_hook.ts`, the
|
|
36
|
+
* kernel-rule list `_lib/kernel_rules.ts`, a `*-dispatcher.sh`, either hook
|
|
37
|
+
* budget file (see `PLUMBING_SOURCE_RE`) — or this gate itself, so it cannot
|
|
38
|
+
* be weakened without its own record. Such a diff must carry a ratification
|
|
39
|
+
* artifact under the ratifications directory with `verdict: ratified`, valid
|
|
40
|
+
* per the ratification-artifact contract.
|
|
37
41
|
*
|
|
38
42
|
* Every kernel diff is gated, not only the authority-EXPANDING ones.
|
|
39
43
|
* ADR-268 § 4 makes the artifact required for authority-expanding edits. Which
|
|
@@ -122,6 +126,67 @@ export const ANCHOR_PATHS: readonly string[] = [
|
|
|
122
126
|
/** Governance hooks: the blocking PreToolUse guards. */
|
|
123
127
|
const GOVERNANCE_HOOK_RE = /^src\/scripts\/hooks\/block_[a-z0-9_]+\.ts$/;
|
|
124
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Hook-plumbing SOURCES — the files that decide which concern runs, on which
|
|
131
|
+
* host, under which budget.
|
|
132
|
+
*
|
|
133
|
+
* `road-to-a-kernel-that-guards-its-plumbing` 1.1. The nine kernel rules were
|
|
134
|
+
* governed and the plumbing that decides whether a guard runs at all was not,
|
|
135
|
+
* so a diff deleting `block-no-verify` from the manifest carried no record
|
|
136
|
+
* while a typo in the rule it enforces carried one. The asymmetry was the
|
|
137
|
+
* defect: a concern removed from `hook_manifest.yaml` is a refusal that stops
|
|
138
|
+
* happening, which is the same authority change as loosening the rule behind
|
|
139
|
+
* it, reached one file earlier.
|
|
140
|
+
*
|
|
141
|
+
* This is the ADR-268 § 4 mechanism EXTENDED, not a second deny. Nothing new
|
|
142
|
+
* refuses a tool call here; the same CI gate simply reads a wider path set,
|
|
143
|
+
* and every property the gate already had — base-revision code, in-repo quorum
|
|
144
|
+
* policy, the whole diff as its unit — carries over unchanged.
|
|
145
|
+
*
|
|
146
|
+
* `dist/hooks/dispatch.js` and `hooks/hooks.json` are BUILD OUTPUTS that no
|
|
147
|
+
* reader in this repository opens — they exist only inside an installed
|
|
148
|
+
* consumer tree — and they have no legitimate hand edit at all, so they are
|
|
149
|
+
* refused at tool-call time by `block_plumbing_writes.ts` rather than ratified
|
|
150
|
+
* here: a record for a file whose every hand edit is illegitimate would be a
|
|
151
|
+
* record of a mistake.
|
|
152
|
+
*
|
|
153
|
+
* road-to-blocking-severities 2.1 WIDENS this from "sources only" to
|
|
154
|
+
* "everything the dispatcher serves at runtime", and the distinction above is
|
|
155
|
+
* why the two compiled tables land here while the two build outputs do not.
|
|
156
|
+
* `src/scripts/hook_manifest.json` and `src/scripts/hooks/host_lowering.json`
|
|
157
|
+
* are committed in THIS tree and are READ IN PREFERENCE to the YAML they were
|
|
158
|
+
* compiled from — `dispatch_hook._load_yaml` and `host_lowering.resolveTable`
|
|
159
|
+
* both serve the compiled body whenever its fingerprint matches. A diff that
|
|
160
|
+
* edits only the JSON therefore changes what every host is told about which
|
|
161
|
+
* concern runs and which slot can refuse, while the gated YAML beside it is
|
|
162
|
+
* untouched. That is the same authority change as editing the source, reached
|
|
163
|
+
* one file later, and before this step it carried no record.
|
|
164
|
+
*
|
|
165
|
+
* Two further files join for the same reason rather than by analogy:
|
|
166
|
+
*
|
|
167
|
+
* - `src/scripts/hooks/dispatch_hook.ts` is the dispatcher itself. Every
|
|
168
|
+
* concern's verdict passes through it, so an edit here can suppress a
|
|
169
|
+
* refusal without touching the manifest that declares it.
|
|
170
|
+
* - `src/scripts/_lib/kernel_rules.ts` is the list of the nine kernel rules.
|
|
171
|
+
* THIS GATE resolves `is_kernel_rule` through it, so a diff removing a name
|
|
172
|
+
* from that list removes a rule from this gate's own reach — the one edit
|
|
173
|
+
* that could quietly narrow the gate while every other path kept working.
|
|
174
|
+
*
|
|
175
|
+
* Both are also denied at tool-call time, `dispatch_hook.ts` through the
|
|
176
|
+
* plumbing guard's source set and `kernel_rules.ts` through the kernel-rule
|
|
177
|
+
* write guard, so the pairing of deny-plus-record matches what the YAML sources
|
|
178
|
+
* already had.
|
|
179
|
+
*
|
|
180
|
+
* The compiled tables are REGENERATED, not hand-edited, by
|
|
181
|
+
* `./scripts-run src/scripts/compile_hook_manifest --table manifest|host-lowering`,
|
|
182
|
+
* which runs as a script rather than as an edit tool call and so is not what
|
|
183
|
+
* either mechanism refuses. A regeneration lands in the same diff as the YAML
|
|
184
|
+
* change that caused it, which already requires a record; the case this closes
|
|
185
|
+
* is the diff where only the JSON moves.
|
|
186
|
+
*/
|
|
187
|
+
const PLUMBING_SOURCE_RE =
|
|
188
|
+
/^(?:src\/scripts\/hook_manifest\.(?:yaml|json)|src\/scripts\/hooks\/host_lowering\.(?:yaml|json)|src\/scripts\/hooks\/dispatch_hook\.ts|src\/scripts\/_lib\/kernel_rules\.ts|src\/scripts\/hooks\/[a-z0-9-]+-dispatcher\.sh|src\/config\/hook-(?:token|latency)-budget\.json)$/;
|
|
189
|
+
|
|
125
190
|
/**
|
|
126
191
|
* A kernel rule, in the source tree or in any projection.
|
|
127
192
|
*
|
|
@@ -141,6 +206,8 @@ const KERNEL_RULE_PATH_RE = /(?:^|\/)rules\/([a-z0-9-]+)\.md$/;
|
|
|
141
206
|
export interface GatedPaths {
|
|
142
207
|
kernelRules: string[];
|
|
143
208
|
governanceHooks: string[];
|
|
209
|
+
/** Hook-plumbing sources — manifest, host lowering, dispatchers, budgets. */
|
|
210
|
+
plumbing: string[];
|
|
144
211
|
self: boolean;
|
|
145
212
|
}
|
|
146
213
|
|
|
@@ -148,6 +215,7 @@ export interface GatedPaths {
|
|
|
148
215
|
export function classifyPaths(files: readonly string[]): GatedPaths {
|
|
149
216
|
const kernelRules: string[] = [];
|
|
150
217
|
const governanceHooks: string[] = [];
|
|
218
|
+
const plumbing: string[] = [];
|
|
151
219
|
let self = false;
|
|
152
220
|
for (const raw of files) {
|
|
153
221
|
const p = raw.replace(/\\/g, '/').trim();
|
|
@@ -171,14 +239,23 @@ export function classifyPaths(files: readonly string[]): GatedPaths {
|
|
|
171
239
|
}
|
|
172
240
|
if (GOVERNANCE_HOOK_RE.test(p)) {
|
|
173
241
|
governanceHooks.push(p);
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (PLUMBING_SOURCE_RE.test(p)) {
|
|
245
|
+
plumbing.push(p);
|
|
174
246
|
}
|
|
175
247
|
}
|
|
176
|
-
return { kernelRules, governanceHooks, self };
|
|
248
|
+
return { kernelRules, governanceHooks, plumbing, self };
|
|
177
249
|
}
|
|
178
250
|
|
|
179
251
|
/** True when anything in the diff requires a ratification artifact. */
|
|
180
252
|
export function requiresRatification(gated: GatedPaths): boolean {
|
|
181
|
-
return
|
|
253
|
+
return (
|
|
254
|
+
gated.kernelRules.length > 0 ||
|
|
255
|
+
gated.governanceHooks.length > 0 ||
|
|
256
|
+
gated.plumbing.length > 0 ||
|
|
257
|
+
gated.self
|
|
258
|
+
);
|
|
182
259
|
}
|
|
183
260
|
|
|
184
261
|
/** Ratification artifacts present in the diff, as repo-relative paths. */
|
|
@@ -253,6 +330,7 @@ export function evaluate(
|
|
|
253
330
|
const gatedSet = new Set<string>([
|
|
254
331
|
...gated.kernelRules,
|
|
255
332
|
...gated.governanceHooks,
|
|
333
|
+
...gated.plumbing,
|
|
256
334
|
...(gated.self ? [SELF_PATH] : []),
|
|
257
335
|
]);
|
|
258
336
|
const artifactSet = new Set(ratificationArtifactsIn(files));
|
|
@@ -286,7 +364,8 @@ export function evaluate(
|
|
|
286
364
|
|
|
287
365
|
if (!requiresRatification(gated)) {
|
|
288
366
|
lines.push(
|
|
289
|
-
'✅ no kernel rule, governance hook or self edit in the
|
|
367
|
+
'✅ no kernel rule, governance hook, hook-plumbing source or self edit in the ' +
|
|
368
|
+
'diff — nothing to ratify',
|
|
290
369
|
);
|
|
291
370
|
close(true);
|
|
292
371
|
return { exitCode: 0, lines, scanned };
|
|
@@ -295,6 +374,7 @@ export function evaluate(
|
|
|
295
374
|
const touched = [
|
|
296
375
|
...gated.kernelRules.map((p) => `kernel rule ${p}`),
|
|
297
376
|
...gated.governanceHooks.map((p) => `governance hook ${p}`),
|
|
377
|
+
...gated.plumbing.map((p) => `hook-plumbing source ${p}`),
|
|
298
378
|
...(gated.self ? ['the ratification mechanism itself (gate, reader, policy or workflow)'] : []),
|
|
299
379
|
];
|
|
300
380
|
lines.push(`Gated surfaces in this diff (${touched.length}):`);
|
|
@@ -446,8 +526,8 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
|
446
526
|
roots: ['<the diff against the base ref>'],
|
|
447
527
|
allowEmpty:
|
|
448
528
|
'EMPTY_VALID: the corpus is one diff. A commit range that changed nothing is a ' +
|
|
449
|
-
'real state, and there is then no kernel rule, governance hook
|
|
450
|
-
'to ratify — the gate has read everything there was.',
|
|
529
|
+
'real state, and there is then no kernel rule, governance hook, plumbing source or ' +
|
|
530
|
+
'mechanism file to ratify — the gate has read everything there was.',
|
|
451
531
|
});
|
|
452
532
|
if (!quiet || result.exitCode !== 0) {
|
|
453
533
|
for (const l of result.lines) {
|