@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
|
@@ -35,12 +35,14 @@
|
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
import * as fs from 'node:fs';
|
|
38
|
+
import * as os from 'node:os';
|
|
38
39
|
import * as path from 'node:path';
|
|
39
40
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
40
41
|
|
|
41
42
|
import YAML from 'yaml';
|
|
42
43
|
|
|
43
|
-
import {
|
|
44
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
45
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
44
46
|
import { py_json_dumps_indent2 } from './_lib/security_lint.js';
|
|
45
47
|
|
|
46
48
|
const _HERE = fileURLToPath(import.meta.url);
|
|
@@ -48,8 +50,16 @@ const _HERE = fileURLToPath(import.meta.url);
|
|
|
48
50
|
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
49
51
|
// Mutable bindings so tests can sandbox the scan target (mirrors the pytest
|
|
50
52
|
// monkeypatch.setattr seam used by sibling lint twins).
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
//
|
|
54
|
+
// `--self-test` needs the same sandbox from a CHILD process, which cannot reach
|
|
55
|
+
// the in-process seam, so the two paths are also readable from the environment.
|
|
56
|
+
// Deliberately env and not argv: the CLI surface is pinned (argparse flags,
|
|
57
|
+
// byte-identical usage lines, unknown arg → exit 2), and a scan root is not
|
|
58
|
+
// something a caller should be able to redirect by typing a flag.
|
|
59
|
+
let WORKFLOWS_DIR = process.env['LINT_WORKFLOW_SECURITY_DIR'] ?? path.join(REPO_ROOT, '.github', 'workflows');
|
|
60
|
+
let ALLOWLIST_PATH =
|
|
61
|
+
process.env['LINT_WORKFLOW_SECURITY_ALLOWLIST'] ??
|
|
62
|
+
path.join(path.dirname(_HERE), 'lint_workflow_security_allowlist.json');
|
|
53
63
|
const ALLOWLIST_CAP = 20;
|
|
54
64
|
|
|
55
65
|
function _setWorkflowsDirForTest(p: string): void {
|
|
@@ -577,8 +587,147 @@ function _usageError(arg: string): string {
|
|
|
577
587
|
);
|
|
578
588
|
}
|
|
579
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Prove, on demand, that the gate's rejections still fire.
|
|
592
|
+
*
|
|
593
|
+
* The CI invocation is warn-only, so the exit code `runSelfTest` reads cannot be
|
|
594
|
+
* moved by a finding there. The cases below therefore drive the two exits the
|
|
595
|
+
* gate really has — 2 for a dead scan scope or an over-cap allowlist, 1 for a
|
|
596
|
+
* HIGH under `--strict` — and pin the warn-only tier itself from the other side:
|
|
597
|
+
* a MEDIUM under `--strict` must still PASS, which is the direction a future
|
|
598
|
+
* re-tiering would silently break.
|
|
599
|
+
*/
|
|
600
|
+
function selfTest(): number {
|
|
601
|
+
const plant = (name: string, files: Record<string, string>): string => {
|
|
602
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `lws-selftest-${name}-`));
|
|
603
|
+
for (const [rel, body] of Object.entries(files)) {
|
|
604
|
+
fs.writeFileSync(path.join(dir, rel), body, 'utf-8');
|
|
605
|
+
}
|
|
606
|
+
return dir;
|
|
607
|
+
};
|
|
608
|
+
const allowlistFile = (entries: unknown[]): string => {
|
|
609
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'lws-selftest-al-'));
|
|
610
|
+
const p = path.join(dir, 'allowlist.json');
|
|
611
|
+
fs.writeFileSync(p, JSON.stringify({ findings: entries }), 'utf-8');
|
|
612
|
+
return p;
|
|
613
|
+
};
|
|
614
|
+
const run = (wfDir: string, args: readonly string[], allowlist?: string): number => {
|
|
615
|
+
const prevDir = process.env['LINT_WORKFLOW_SECURITY_DIR'];
|
|
616
|
+
const prevAl = process.env['LINT_WORKFLOW_SECURITY_ALLOWLIST'];
|
|
617
|
+
process.env['LINT_WORKFLOW_SECURITY_DIR'] = wfDir;
|
|
618
|
+
if (allowlist !== undefined) {
|
|
619
|
+
process.env['LINT_WORKFLOW_SECURITY_ALLOWLIST'] = allowlist;
|
|
620
|
+
}
|
|
621
|
+
try {
|
|
622
|
+
return runGateCli(
|
|
623
|
+
REPO_ROOT,
|
|
624
|
+
path.join('src', 'scripts', 'lint_workflow_security.ts'),
|
|
625
|
+
args,
|
|
626
|
+
REPO_ROOT,
|
|
627
|
+
);
|
|
628
|
+
} finally {
|
|
629
|
+
if (prevDir === undefined) {
|
|
630
|
+
delete process.env['LINT_WORKFLOW_SECURITY_DIR'];
|
|
631
|
+
} else {
|
|
632
|
+
process.env['LINT_WORKFLOW_SECURITY_DIR'] = prevDir;
|
|
633
|
+
}
|
|
634
|
+
if (prevAl === undefined) {
|
|
635
|
+
delete process.env['LINT_WORKFLOW_SECURITY_ALLOWLIST'];
|
|
636
|
+
} else {
|
|
637
|
+
process.env['LINT_WORKFLOW_SECURITY_ALLOWLIST'] = prevAl;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
const HIGH_WF = [
|
|
643
|
+
'on:',
|
|
644
|
+
' pull_request_target:',
|
|
645
|
+
'jobs:',
|
|
646
|
+
' build:',
|
|
647
|
+
' steps:',
|
|
648
|
+
' - uses: actions/checkout@0000000000000000000000000000000000000000',
|
|
649
|
+
' with:',
|
|
650
|
+
' persist-credentials: false',
|
|
651
|
+
' ref: ${{ github.event.pull_request.head.sha }}',
|
|
652
|
+
'',
|
|
653
|
+
].join('\n');
|
|
654
|
+
// Unpinned third-party action — MEDIUM, and MEDIUM alone.
|
|
655
|
+
const MEDIUM_WF = [
|
|
656
|
+
'on:',
|
|
657
|
+
' push:',
|
|
658
|
+
'jobs:',
|
|
659
|
+
' build:',
|
|
660
|
+
' steps:',
|
|
661
|
+
' - uses: somevendor/action@v1',
|
|
662
|
+
'',
|
|
663
|
+
].join('\n');
|
|
664
|
+
const CLEAN_WF = [
|
|
665
|
+
'on:',
|
|
666
|
+
' push:',
|
|
667
|
+
'jobs:',
|
|
668
|
+
' build:',
|
|
669
|
+
' steps:',
|
|
670
|
+
' - uses: actions/checkout@0000000000000000000000000000000000000000',
|
|
671
|
+
' with:',
|
|
672
|
+
' persist-credentials: false',
|
|
673
|
+
' - run: npm ci --ignore-scripts',
|
|
674
|
+
'',
|
|
675
|
+
].join('\n');
|
|
676
|
+
|
|
677
|
+
return runSelfTest({
|
|
678
|
+
gate: 'lint_workflow_security',
|
|
679
|
+
minCases: 5,
|
|
680
|
+
minRejectCases: 3,
|
|
681
|
+
cases: [
|
|
682
|
+
{
|
|
683
|
+
name: 'an empty workflows directory is refused, not certified "0 HIGH, 0 MEDIUM"',
|
|
684
|
+
expect: 'reject',
|
|
685
|
+
run: () => run(plant('empty', {}), []),
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
name: 'a pull_request_target checkout of the untrusted ref fails under --strict',
|
|
689
|
+
expect: 'reject',
|
|
690
|
+
run: () => run(plant('high', { 'bad.yml': HIGH_WF }), ['--strict']),
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
name: 'an over-cap allowlist fails rather than suppressing silently',
|
|
694
|
+
expect: 'reject',
|
|
695
|
+
run: () =>
|
|
696
|
+
run(
|
|
697
|
+
plant('cap', { 'ok.yml': CLEAN_WF }),
|
|
698
|
+
[],
|
|
699
|
+
allowlistFile(
|
|
700
|
+
Array.from({ length: ALLOWLIST_CAP + 1 }, (_, n) => ({
|
|
701
|
+
workflow: `w${String(n)}.yml`,
|
|
702
|
+
rule: 'unpinned-action',
|
|
703
|
+
})),
|
|
704
|
+
),
|
|
705
|
+
),
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
name: 'a MEDIUM under --strict still PASSES — the tier split is real, not decorative',
|
|
709
|
+
expect: 'accept',
|
|
710
|
+
run: () => run(plant('medium', { 'med.yml': MEDIUM_WF }), ['--strict']),
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
name: 'a clean workflow passes under --strict',
|
|
714
|
+
expect: 'accept',
|
|
715
|
+
run: () => run(plant('clean', { 'ok.yml': CLEAN_WF }), ['--strict']),
|
|
716
|
+
},
|
|
717
|
+
],
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
580
721
|
export function main(argv?: string[]): number {
|
|
581
|
-
const
|
|
722
|
+
const rawArgv = argv ?? process.argv.slice(2);
|
|
723
|
+
if (rawArgv.includes('--self-test')) {
|
|
724
|
+
if (process.env['GATE_SELF_TEST_CHILD'] === '1') {
|
|
725
|
+
process.stderr.write('lint_workflow_security: --self-test does not recurse\n');
|
|
726
|
+
return 2;
|
|
727
|
+
}
|
|
728
|
+
return selfTest();
|
|
729
|
+
}
|
|
730
|
+
const parsed = _parseArgs(rawArgv);
|
|
582
731
|
if (parsed.exitCode !== undefined) {
|
|
583
732
|
return parsed.exitCode;
|
|
584
733
|
}
|
|
@@ -600,7 +749,14 @@ export function main(argv?: string[]): number {
|
|
|
600
749
|
const yml = _sortedGlob('.yml');
|
|
601
750
|
const yaml = _sortedGlob('.yaml');
|
|
602
751
|
try {
|
|
603
|
-
assertScanned
|
|
752
|
+
// `reportScanned`, not `assertScanned`: the gate now carries a floor in
|
|
753
|
+
// src/config/gate-coverage.yml, and the guard there reads the
|
|
754
|
+
// machine-readable `scanned:` line. Asserting without publishing leaves
|
|
755
|
+
// the gate invisible to the coverage guard — the half-adoption
|
|
756
|
+
// `_lib/scan_scope.reportScanned` was written to close. The line goes to
|
|
757
|
+
// stdout unconditionally, `--quiet` included, because CI passes
|
|
758
|
+
// `--quiet` and a count only visible without it is not a count.
|
|
759
|
+
reportScanned({
|
|
604
760
|
gate: 'lint_workflow_security',
|
|
605
761
|
scanned: yml.length + yaml.length,
|
|
606
762
|
units: 'workflow file(s)',
|
|
@@ -283,6 +283,59 @@
|
|
|
283
283
|
"readOnlyHint": false
|
|
284
284
|
}
|
|
285
285
|
},
|
|
286
|
+
{
|
|
287
|
+
"name": "graph_node",
|
|
288
|
+
"description": "One symbol in full: where it is declared, what reaches it, what it reaches, and how connected it is. Resolves EXACTLY (node id, then label) and refuses anything it cannot — it never scores free text, so an answer is always about the node you named.",
|
|
289
|
+
"side_effect": "ro",
|
|
290
|
+
"implemented_on": [
|
|
291
|
+
"stdio"
|
|
292
|
+
],
|
|
293
|
+
"input_schema": {
|
|
294
|
+
"type": "object",
|
|
295
|
+
"required": [
|
|
296
|
+
"id"
|
|
297
|
+
],
|
|
298
|
+
"properties": {
|
|
299
|
+
"id": {
|
|
300
|
+
"type": "string",
|
|
301
|
+
"description": "Node id `<relpath>#<sym>` or an exact label."
|
|
302
|
+
},
|
|
303
|
+
"direction": {
|
|
304
|
+
"type": "string",
|
|
305
|
+
"enum": [
|
|
306
|
+
"in",
|
|
307
|
+
"out",
|
|
308
|
+
"both"
|
|
309
|
+
],
|
|
310
|
+
"default": "both",
|
|
311
|
+
"description": "Which edges to walk. `in` = who reaches it, `out` = what it reaches."
|
|
312
|
+
},
|
|
313
|
+
"depth": {
|
|
314
|
+
"type": "integer",
|
|
315
|
+
"minimum": 1,
|
|
316
|
+
"maximum": 3,
|
|
317
|
+
"default": 1,
|
|
318
|
+
"description": "Hop limit."
|
|
319
|
+
},
|
|
320
|
+
"relation": {
|
|
321
|
+
"type": "string",
|
|
322
|
+
"enum": [
|
|
323
|
+
"calls",
|
|
324
|
+
"imports",
|
|
325
|
+
"uses",
|
|
326
|
+
"inherits",
|
|
327
|
+
"member",
|
|
328
|
+
"tests"
|
|
329
|
+
],
|
|
330
|
+
"description": "Restrict to one relation. Omit for all of them."
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
"additionalProperties": false
|
|
334
|
+
},
|
|
335
|
+
"annotations": {
|
|
336
|
+
"readOnlyHint": true
|
|
337
|
+
}
|
|
338
|
+
},
|
|
286
339
|
{
|
|
287
340
|
"name": "graph_path",
|
|
288
341
|
"description": "The shortest relation chain between two symbols, direction preserved. Answers \"how does A reach B\" without reading the files between. `(no path found)` when unconnected is an answer.",
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
2
|
+
* The code-graph MCP tools (`road-to-a-graph-that-is-shipped` 4.1).
|
|
3
|
+
*
|
|
4
|
+
* `graph_impact`, `graph_tests_for`, `graph_dead`, `graph_query`, `graph_path`
|
|
5
|
+
* — and `graph_node`, added by `road-to-a-graph-that-feeds-the-gate` 3.1. The
|
|
6
|
+
* first five all answer about a NEIGHBOURHOOD or a SET; none answered "where
|
|
7
|
+
* does this live, who reaches it, what does it reach, how connected is it",
|
|
8
|
+
* which is the question an agent asks first and had to assemble from two calls
|
|
9
|
+
* and a file read.
|
|
3
10
|
*
|
|
4
|
-
* `graph_impact`, `graph_tests_for`, `graph_dead`, `graph_query`, `graph_path`.
|
|
5
11
|
* They are the agent-facing half of Phase 3: the verbs exist on the CLI and an
|
|
6
12
|
* agent that has to shell out to reach them will not, so the engine's answers
|
|
7
13
|
* were unreachable from the surface the consumer actually talks to. Risk-Register
|
|
@@ -39,7 +45,15 @@ import { changedFiles } from '../code_graph/cli.js';
|
|
|
39
45
|
import { detectSources, graphState, NATIVE_CACHE_REL, pickSource } from '../code_graph/detect.js';
|
|
40
46
|
import { resolvePath } from './path_util.js';
|
|
41
47
|
import { isTestFile } from '../code_graph/build.js';
|
|
42
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
loadGraph,
|
|
50
|
+
type LoadedGraph,
|
|
51
|
+
node as graphNodeVerb,
|
|
52
|
+
type NodeOptions,
|
|
53
|
+
path as graphPathVerb,
|
|
54
|
+
query as graphQueryVerb,
|
|
55
|
+
} from '../code_graph/query.js';
|
|
56
|
+
import type { Relation } from '../code_graph/types.js';
|
|
43
57
|
import {
|
|
44
58
|
dead,
|
|
45
59
|
entryPointsFromFile,
|
|
@@ -97,6 +111,16 @@ function str(args: Record<string, unknown>, key: string): string {
|
|
|
97
111
|
return typeof v === 'string' ? v.trim() : '';
|
|
98
112
|
}
|
|
99
113
|
|
|
114
|
+
/**
|
|
115
|
+
* The closed relation vocabulary, as a schema enum.
|
|
116
|
+
*
|
|
117
|
+
* Spelled out rather than derived from the `Relation` union, which erases at
|
|
118
|
+
* compile time — and pinned by a test against that union so the two cannot
|
|
119
|
+
* drift. An enum that silently lost a value would turn a legal filter into a
|
|
120
|
+
* rejected argument.
|
|
121
|
+
*/
|
|
122
|
+
const RELATIONS = ['calls', 'imports', 'uses', 'inherits', 'member', 'tests'] as const;
|
|
123
|
+
|
|
100
124
|
function num(args: Record<string, unknown>, key: string, dflt: number): number {
|
|
101
125
|
const v = args[key];
|
|
102
126
|
return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : dflt;
|
|
@@ -263,6 +287,51 @@ export const GRAPH_TOOLS: Record<string, BuiltinTool> = {
|
|
|
263
287
|
},
|
|
264
288
|
},
|
|
265
289
|
|
|
290
|
+
graph_node: {
|
|
291
|
+
name: 'graph_node',
|
|
292
|
+
side_effect: 'ro',
|
|
293
|
+
description:
|
|
294
|
+
'One symbol in full: where it is declared, what reaches it, what it ' +
|
|
295
|
+
'reaches, and how connected it is. Resolves EXACTLY (node id, then ' +
|
|
296
|
+
'label) and refuses anything it cannot — it never scores free text, ' +
|
|
297
|
+
'so an answer is always about the node you named.',
|
|
298
|
+
input_schema: {
|
|
299
|
+
type: 'object',
|
|
300
|
+
required: ['id'],
|
|
301
|
+
properties: {
|
|
302
|
+
id: { type: 'string', description: 'Node id `<relpath>#<sym>` or an exact label.' },
|
|
303
|
+
direction: {
|
|
304
|
+
type: 'string',
|
|
305
|
+
enum: ['in', 'out', 'both'],
|
|
306
|
+
default: 'both',
|
|
307
|
+
description: 'Which edges to walk. `in` = who reaches it, `out` = what it reaches.',
|
|
308
|
+
},
|
|
309
|
+
depth: { type: 'integer', minimum: 1, maximum: 3, default: 1, description: 'Hop limit.' },
|
|
310
|
+
relation: {
|
|
311
|
+
type: 'string',
|
|
312
|
+
enum: RELATIONS,
|
|
313
|
+
description: 'Restrict to one relation. Omit for all of them.',
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
additionalProperties: false,
|
|
317
|
+
},
|
|
318
|
+
handler: async (args, root) => {
|
|
319
|
+
const id = str(args, 'id');
|
|
320
|
+
if (id === '') return { status: 'error', error: 'id must be a non-empty string' };
|
|
321
|
+
const staleness = graphState(root);
|
|
322
|
+
const opts: NodeOptions = {};
|
|
323
|
+
const dir = str(args, 'direction');
|
|
324
|
+
if (dir === 'in' || dir === 'out' || dir === 'both') opts.direction = dir;
|
|
325
|
+
// `num` clamps at >0 only; the 1-3 band is the verb's, so an
|
|
326
|
+
// out-of-band value is clamped there rather than rejected here —
|
|
327
|
+
// two places enforcing one band is how they drift apart.
|
|
328
|
+
opts.depth = num(args, 'depth', 1);
|
|
329
|
+
const rel = str(args, 'relation');
|
|
330
|
+
if ((RELATIONS as readonly string[]).includes(rel)) opts.relation = rel as Relation;
|
|
331
|
+
return withGraph(root, (g) => ({ staleness, ...graphNodeVerb(g, id, opts) }));
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
|
|
266
335
|
graph_path: {
|
|
267
336
|
name: 'graph_path',
|
|
268
337
|
side_effect: 'ro',
|
|
@@ -69,6 +69,22 @@ export interface SkillPrompt {
|
|
|
69
69
|
readonly kind: PromptKind;
|
|
70
70
|
readonly recommended_for_user_types: readonly string[];
|
|
71
71
|
readonly user_type_match: UserTypeMatch;
|
|
72
|
+
/**
|
|
73
|
+
* Declared parameters, from the frontmatter `inputs:` block.
|
|
74
|
+
*
|
|
75
|
+
* Empty for every artifact that declares none, which is the whole corpus
|
|
76
|
+
* today — so `arguments: []` on the wire stays the behaviour for an
|
|
77
|
+
* undeclared prompt rather than becoming a special case
|
|
78
|
+
* (road-to-an-invocation-contract-that-reaches-the-wire 3.2).
|
|
79
|
+
*/
|
|
80
|
+
readonly inputs: readonly PromptInput[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** One declared parameter, reduced to what the MCP `arguments` shape carries. */
|
|
84
|
+
export interface PromptInput {
|
|
85
|
+
readonly name: string;
|
|
86
|
+
readonly description: string;
|
|
87
|
+
readonly required: boolean;
|
|
72
88
|
}
|
|
73
89
|
|
|
74
90
|
/** Walk up from this file to the repo root (parent of `scripts/`). */
|
|
@@ -92,6 +108,124 @@ export function _project_root(): string {
|
|
|
92
108
|
* Avoids a YAML dependency for Phase 1; the frontmatter shape is
|
|
93
109
|
* enforced by `task lint-skills` upstream.
|
|
94
110
|
*/
|
|
111
|
+
/** The raw frontmatter block of a document, or `''` when it has none. */
|
|
112
|
+
export function _frontmatter_text(text: string): string {
|
|
113
|
+
if (!text.startsWith('---\n')) return '';
|
|
114
|
+
const parts = _splitMax(text, '---\n', 2);
|
|
115
|
+
return parts.length < 3 ? '' : (parts[1] as string);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Parse the frontmatter `inputs:` block out of raw frontmatter text.
|
|
120
|
+
*
|
|
121
|
+
* WHY THIS EXISTS RATHER THAN A YAML CALL. `_strip_frontmatter` is a flat
|
|
122
|
+
* `key: value` line scanner and cannot represent a nested list — `inputs:`
|
|
123
|
+
* would land as an empty string and its `- name: x` lines as stray keys. The
|
|
124
|
+
* MCP server is deliberately stdlib-only and is bundled for the wire, so
|
|
125
|
+
* pulling a YAML parser in to read one optional block would pay a dependency
|
|
126
|
+
* on every install for a block almost nothing declares yet.
|
|
127
|
+
*
|
|
128
|
+
* IT READS ONE SHAPE AND REFUSES THE REST. Accepted:
|
|
129
|
+
*
|
|
130
|
+
* inputs:
|
|
131
|
+
* - name: target
|
|
132
|
+
* type: string
|
|
133
|
+
* required: true
|
|
134
|
+
* description: What to act on.
|
|
135
|
+
*
|
|
136
|
+
* Refused, by yielding NOTHING for the whole block: the flow form
|
|
137
|
+
* (`inputs: [{name: a}]`), a block scalar (`description: >`), and any nested
|
|
138
|
+
* mapping under an item key. Refusing is not silent — `check_inputs_parity`
|
|
139
|
+
* compares this reader against a real YAML parse for every declaring artifact
|
|
140
|
+
* and FAILS the build on any difference, so an unsupported form is a red gate
|
|
141
|
+
* with a named remedy rather than a wrong argument on the wire.
|
|
142
|
+
*
|
|
143
|
+
* That gate is the answer to the defect an independent review found here: the
|
|
144
|
+
* key scan used to run at any depth, so a `default:` MAPPING whose first child
|
|
145
|
+
* was `name:` overwrote the parameter's own name and the server offered a host
|
|
146
|
+
* an argument that did not exist. The header promised "no guessed input" while
|
|
147
|
+
* the code guessed. Depth is now tracked, and where this reader cannot be sure
|
|
148
|
+
* it declines and the parity gate makes the decline visible.
|
|
149
|
+
*/
|
|
150
|
+
export function _parse_inputs(fm: string): PromptInput[] {
|
|
151
|
+
const lines = fm.split('\n');
|
|
152
|
+
let i = lines.findIndex((l) => /^inputs:/.test(l));
|
|
153
|
+
if (i === -1) return [];
|
|
154
|
+
// The flow form carries its payload on the `inputs:` line itself. This
|
|
155
|
+
// reader does not parse it; the parity gate turns that into a failure.
|
|
156
|
+
if (!/^inputs:\s*$/.test(lines[i] as string)) return [];
|
|
157
|
+
|
|
158
|
+
const out: PromptInput[] = [];
|
|
159
|
+
let current: { name?: string; description?: string; required?: boolean } | null = null;
|
|
160
|
+
/** Indent of the key lines belonging to the item being read. */
|
|
161
|
+
let keyIndent: number | null = null;
|
|
162
|
+
let refused = false;
|
|
163
|
+
|
|
164
|
+
const flush = (): void => {
|
|
165
|
+
if (current?.name !== undefined) {
|
|
166
|
+
out.push({
|
|
167
|
+
name: current.name,
|
|
168
|
+
description: current.description ?? '',
|
|
169
|
+
required: current.required === true,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
current = null;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const clean = (raw: string): string => {
|
|
176
|
+
const v = raw.trim();
|
|
177
|
+
// An unquoted trailing comment is not part of the value — the same strip
|
|
178
|
+
// `_strip_frontmatter` applies, kept consistent deliberately.
|
|
179
|
+
const hashed = /^(?!["'])([^#]*?)\s+#.*$/.exec(v);
|
|
180
|
+
return _stripQuotes((hashed === null ? v : (hashed[1] ?? '')).trim());
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
for (i += 1; i < lines.length && !refused; i += 1) {
|
|
184
|
+
const line = lines[i] as string;
|
|
185
|
+
if (line.trim() === '') continue;
|
|
186
|
+
// A comment at any column is not block content and does not end the block.
|
|
187
|
+
if (/^\s*#/.test(line)) continue;
|
|
188
|
+
// A non-indented line ends the block.
|
|
189
|
+
if (!/^\s/.test(line)) break;
|
|
190
|
+
|
|
191
|
+
const indent = (/^(\s*)/.exec(line) as RegExpExecArray)[1]!.replace(/\t/g, ' ').length;
|
|
192
|
+
|
|
193
|
+
const item = /^\s*-\s+([A-Za-z_]\w*):\s*(.*)$/.exec(line);
|
|
194
|
+
if (item !== null) {
|
|
195
|
+
flush();
|
|
196
|
+
current = {};
|
|
197
|
+
keyIndent = line.indexOf('-') + 2;
|
|
198
|
+
if (item[1] === 'name') current.name = clean(item[2] ?? '');
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const kv = /^\s+([A-Za-z_]\w*):\s*(.*)$/.exec(line);
|
|
203
|
+
if (kv === null || current === null || keyIndent === null) continue;
|
|
204
|
+
// Deeper than the item's own keys: a nested mapping or sequence this
|
|
205
|
+
// reader does not model. Decline the whole block rather than absorb it.
|
|
206
|
+
if (indent > keyIndent) {
|
|
207
|
+
refused = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
const key = kv[1] as string;
|
|
211
|
+
const rawValue = (kv[2] ?? '').trim();
|
|
212
|
+
// A block scalar or an empty value means the real content is on the
|
|
213
|
+
// following lines, which this reader does not join.
|
|
214
|
+
if (rawValue === '' || rawValue === '>' || rawValue === '|') {
|
|
215
|
+
refused = true;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
const value = clean(rawValue);
|
|
219
|
+
if (key === 'name') current.name = value;
|
|
220
|
+
else if (key === 'description') current.description = value;
|
|
221
|
+
else if (key === 'required') current.required = value.toLowerCase() === 'true';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (refused) return [];
|
|
225
|
+
flush();
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
|
|
95
229
|
export function _strip_frontmatter(text: string): [Record<string, string>, string] {
|
|
96
230
|
if (!text.startsWith('---\n')) {
|
|
97
231
|
return [{}, text];
|
|
@@ -365,6 +499,7 @@ function _load_file(p: string, kind: PromptKind, fallback_name: string): SkillPr
|
|
|
365
499
|
kind,
|
|
366
500
|
recommended_for_user_types: _parse_inline_array(meta.recommended_for_user_types ?? ''),
|
|
367
501
|
user_type_match: '',
|
|
502
|
+
inputs: _parse_inputs(_frontmatter_text(text)),
|
|
368
503
|
};
|
|
369
504
|
}
|
|
370
505
|
|
|
@@ -548,7 +683,13 @@ export function to_mcp_prompt_meta(prompt: SkillPrompt): Record<string, unknown>
|
|
|
548
683
|
name: wire,
|
|
549
684
|
title: prompt.name,
|
|
550
685
|
description: prompt.description,
|
|
551
|
-
|
|
686
|
+
// Derived from the declaration, never invented. An artifact that
|
|
687
|
+
// declares nothing still serves `[]` — see `_parse_inputs`.
|
|
688
|
+
arguments: prompt.inputs.map((i) => ({
|
|
689
|
+
name: i.name,
|
|
690
|
+
description: i.description,
|
|
691
|
+
required: i.required,
|
|
692
|
+
})),
|
|
552
693
|
_meta: meta,
|
|
553
694
|
};
|
|
554
695
|
}
|
|
@@ -117,6 +117,59 @@ export function mcnemarExactP(gained: number, lost: number): number {
|
|
|
117
117
|
|
|
118
118
|
const pp = (hits: number, total: number): number => (total === 0 ? 0 : (hits / total) * 100);
|
|
119
119
|
|
|
120
|
+
/** The inputs the pre-registered verdict function reads, and nothing else. */
|
|
121
|
+
export interface VerdictInputs {
|
|
122
|
+
readonly deltaRecall: number;
|
|
123
|
+
readonly deltaFalse: number;
|
|
124
|
+
readonly p: number;
|
|
125
|
+
readonly gained: number;
|
|
126
|
+
readonly lost: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The pre-registered verdict function, in its pre-registered ORDER.
|
|
131
|
+
*
|
|
132
|
+
* Extracted from `measure` on 2026-10-04 so the order can be tested against
|
|
133
|
+
* chosen inputs rather than against whatever the live corpus happens to
|
|
134
|
+
* produce. The behaviour is unchanged, deliberately: this is a move, not a
|
|
135
|
+
* rewrite, and the bars it reads are the same module-level constants.
|
|
136
|
+
*
|
|
137
|
+
* WHY IT HAD TO MOVE. The order is load-bearing — power floor, then guard,
|
|
138
|
+
* then primary — and the only thing pinning it was a test asserting that the
|
|
139
|
+
* LIVE run happened to be a case that discriminates: primary met AND guard
|
|
140
|
+
* breached, so a function checking the primary first would wrongly say
|
|
141
|
+
* `signal`. That witness is a property of the corpus, not of the code, and the
|
|
142
|
+
* corpus grows whenever a skill gains a trigger file. On 2026-10-04 one such
|
|
143
|
+
* growth moved delta-recall from 5.128 to 4.608 and the witness was gone,
|
|
144
|
+
* leaving the ordering guarded by nothing. Tested here against chosen inputs,
|
|
145
|
+
* the discriminating case is always available and no future corpus growth can
|
|
146
|
+
* take it away.
|
|
147
|
+
*/
|
|
148
|
+
export function verdictOf(i: VerdictInputs): { verdict: Verdict; reason: string } {
|
|
149
|
+
if (i.gained + i.lost < POWER_FLOOR_DISCORDANT) {
|
|
150
|
+
return {
|
|
151
|
+
verdict: 'underpowered',
|
|
152
|
+
reason: `${i.gained + i.lost} discordant positive pairs < power floor ${POWER_FLOOR_DISCORDANT}`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (i.deltaFalse > FALSE_ACTIVATION_GUARD_PP) {
|
|
156
|
+
return {
|
|
157
|
+
verdict: 'harmful',
|
|
158
|
+
reason: `false activation +${i.deltaFalse.toFixed(2)} pp breaches the +${FALSE_ACTIVATION_GUARD_PP.toFixed(1)} pp guard`,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (i.deltaRecall >= RECALL_GAIN_BAR_PP && i.p < ALPHA) {
|
|
162
|
+
return {
|
|
163
|
+
verdict: 'signal',
|
|
164
|
+
reason: `recall +${i.deltaRecall.toFixed(2)} pp at p=${i.p.toExponential(2)}`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
verdict: 'null',
|
|
169
|
+
reason: `recall +${i.deltaRecall.toFixed(2)} pp at p=${i.p.toExponential(2)} does not clear +${RECALL_GAIN_BAR_PP.toFixed(1)} pp and p<${ALPHA}`,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
120
173
|
export function measure(repo = REPO, k = K): Measurement {
|
|
121
174
|
const catalogue: CatalogueEntry[] = loadCatalogue(repo);
|
|
122
175
|
const cases: CorpusCase[] = loadTrainCases(repo);
|
|
@@ -170,22 +223,7 @@ export function measure(repo = REPO, k = K): Measurement {
|
|
|
170
223
|
(falsePp['description+body'] as number) - (falsePp['description'] as number);
|
|
171
224
|
const p = mcnemarExactP(gained, lost);
|
|
172
225
|
|
|
173
|
-
|
|
174
|
-
let verdict: Verdict;
|
|
175
|
-
let reason: string;
|
|
176
|
-
if (gained + lost < POWER_FLOOR_DISCORDANT) {
|
|
177
|
-
verdict = 'underpowered';
|
|
178
|
-
reason = `${gained + lost} discordant positive pairs < power floor ${POWER_FLOOR_DISCORDANT}`;
|
|
179
|
-
} else if (deltaFalse > FALSE_ACTIVATION_GUARD_PP) {
|
|
180
|
-
verdict = 'harmful';
|
|
181
|
-
reason = `false activation +${deltaFalse.toFixed(2)} pp breaches the +${FALSE_ACTIVATION_GUARD_PP.toFixed(1)} pp guard`;
|
|
182
|
-
} else if (deltaRecall >= RECALL_GAIN_BAR_PP && p < ALPHA) {
|
|
183
|
-
verdict = 'signal';
|
|
184
|
-
reason = `recall +${deltaRecall.toFixed(2)} pp at p=${p.toExponential(2)}`;
|
|
185
|
-
} else {
|
|
186
|
-
verdict = 'null';
|
|
187
|
-
reason = `recall +${deltaRecall.toFixed(2)} pp at p=${p.toExponential(2)} does not clear +${RECALL_GAIN_BAR_PP.toFixed(1)} pp and p<${ALPHA}`;
|
|
188
|
-
}
|
|
226
|
+
const { verdict, reason } = verdictOf({ deltaRecall, deltaFalse, p, gained, lost });
|
|
189
227
|
|
|
190
228
|
return {
|
|
191
229
|
k,
|