@event4u/agent-config 16.2.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 +89 -237
- 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 +4 -4
- 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/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/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/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/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-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- 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/monorepo-workspace/SKILL.md +1 -1
- 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 +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- 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-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -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-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
- 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-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
- 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 +1167 -234
- 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 +127 -75
- 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 +5357 -6656
- package/dist/hooks/dispatch.sha256 +1 -1
- 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 +2080 -1024
- 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 +31965 -27154
- 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 +6 -0
- package/dist/shared/skillRanking.js +74 -13
- package/docs/contracts/settings-classes.md +7 -5
- package/package.json +1 -1
- 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/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +62 -22
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +96 -3
- package/src/config/gate-violation-baselines.json +17 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/routing-coverage-seed.json +24 -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 +23 -71
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- 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/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_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/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/prompt_shape.ts +46 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- 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/skill_origin.ts +254 -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 +77 -2
- 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/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +116 -4
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_kernel_edit_ratified.ts +49 -11
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- 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 +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +150 -9
- package/src/scripts/hooks/block_config_weakening.ts +67 -2
- package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/rule_inject_hook.ts +757 -63
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
- package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +72 -185
- 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_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_rule_law_section.ts +517 -0
- 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/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_single_token_triggers.ts +277 -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/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/self_review_gate.ts +62 -7
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- 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 -5
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +117 -11
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
|
@@ -18,11 +18,10 @@
|
|
|
18
18
|
* target dir of your choosing — it never overwrites the live `.claude/` /
|
|
19
19
|
* `.augment/` projections.
|
|
20
20
|
*
|
|
21
|
-
* NOTE
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* file by twin-parity.
|
|
21
|
+
* NOTE: the thin-entry pointer literal moved with the mechanism — it is
|
|
22
|
+
* `BODY_LINK_PREFIX` in `_lib/thin_rules.ts` now, so the twin-parity argument
|
|
23
|
+
* that exempted it from the ADR-051 legacy-path guard belongs to THAT file and
|
|
24
|
+
* no longer describes this one, which holds the string nowhere.
|
|
26
25
|
*
|
|
27
26
|
* Historical quirks are preserved deliberately — tests and downstream consumers pin the exact behaviour.
|
|
28
27
|
*
|
|
@@ -34,299 +33,20 @@ import * as fs from 'node:fs';
|
|
|
34
33
|
import * as path from 'node:path';
|
|
35
34
|
import process from 'node:process';
|
|
36
35
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
37
|
-
import { pathOnlyRuleIds, triggerlessRuleIds, } from './_lib/rule_injection.js';
|
|
38
36
|
import * as token_count from './_lib/token_count.js';
|
|
39
|
-
const _HERE = fileURLToPath(import.meta.url);
|
|
40
|
-
// REPO_ROOT = Path(__file__).resolve().parent.parent.parent — three dirs up
|
|
41
|
-
// from src/scripts/<file>.
|
|
42
|
-
export const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
43
|
-
export const RULES_SOURCE = path.join(REPO_ROOT, 'dist/agent-src', 'rules');
|
|
44
|
-
export const ROUTER = path.join(REPO_ROOT, 'dist', 'router.json');
|
|
45
|
-
/** `sorted(dir.glob("*.md"))` — non-recursive, lexically sorted abs paths. */
|
|
46
|
-
function _globSortedMd(dir) {
|
|
47
|
-
let names;
|
|
48
|
-
try {
|
|
49
|
-
names = fs.readdirSync(dir);
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
return [];
|
|
53
|
-
}
|
|
54
|
-
const out = names.filter((n) => n.endsWith('.md')).map((n) => path.join(dir, n));
|
|
55
|
-
out.sort();
|
|
56
|
-
return out;
|
|
57
|
-
}
|
|
58
|
-
/** The always-full-bodied set — authoritative kernel list from the router. */
|
|
59
|
-
export function kernel_ids() {
|
|
60
|
-
const data = JSON.parse(fs.readFileSync(ROUTER, 'utf-8'));
|
|
61
|
-
const kernel = data.kernel;
|
|
62
|
-
if (Array.isArray(kernel)) {
|
|
63
|
-
return new Set(kernel.map((x) => String(x)));
|
|
64
|
-
}
|
|
65
|
-
return new Set();
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Tier rules the router gives NO trigger at all.
|
|
69
|
-
*
|
|
70
|
-
* These cannot be delivered on a match, so thinning them would remove a body
|
|
71
|
-
* that nothing can ever put back — a silent hole rather than a saving. They
|
|
72
|
-
* project full-bodied, and `measure` reports them by name so the residue is
|
|
73
|
-
* visible instead of being absorbed into the pointer count
|
|
74
|
-
* (road-to-trigger-delivered-rule-bodies 1.3).
|
|
75
|
-
*/
|
|
76
|
-
/**
|
|
77
|
-
* Rules whose ONLY triggers are path-shaped — reachable from `pre_tool_use`
|
|
78
|
-
* and from no other slot (road-to-delivery-for-every-host 3.2).
|
|
79
|
-
*
|
|
80
|
-
* They must never be thinned while the delivery concern is NOT bound on
|
|
81
|
-
* `pre_tool_use`, because a stub plus a slot nobody listens on is a rule that
|
|
82
|
-
* reaches the model at no scope at all. This is the same failure the
|
|
83
|
-
* `no_trigger_ids` exemption prevents, one step out: there the rule has nothing
|
|
84
|
-
* to match on, here it has nothing to match ON.
|
|
85
|
-
*
|
|
86
|
-
* Stated as a PROPERTY rather than a list of ids. If the concern is ever bound
|
|
87
|
-
* on `pre_tool_use` again, this exemption is what should be reconsidered — not
|
|
88
|
-
* three names someone has to remember.
|
|
89
|
-
*
|
|
90
|
-
* WHAT THIS EXEMPTION DOES **NOT** COVER — recorded 2026-09-08, R2 finding 1,
|
|
91
|
-
* because the silence read as coverage. The predicate is `every` trigger
|
|
92
|
-
* path-shaped. A rule with BOTH path and non-path triggers is therefore THINNED,
|
|
93
|
-
* and its path-shaped half then has no carrier at all: the stub carries no
|
|
94
|
-
* frontmatter (`condense.ts` writes it with `_writeText`, bypassing
|
|
95
|
-
* `_emit_claude_rule`'s host-native `paths:` key), `pre_tool_use` lost the
|
|
96
|
-
* binding under owner ruling E2, and `user_prompt_submit` never populates
|
|
97
|
-
* `openFiles`. Measured over the current `dist/router.json`: **18 such rules**,
|
|
98
|
-
* all non-kernel and all thinned — augment-edit-discipline, design-fidelity,
|
|
99
|
-
* doc-screenshot-hygiene, domain-adoption-policy,
|
|
100
|
-
* framework-neutrality-in-generic-skills, image-likeness-and-rights,
|
|
101
|
-
* laravel-translations, lethal-trifecta-guard, linked-projects-onboarding-gate,
|
|
102
|
-
* low-impact-corpus-privacy-floor, markdown-safe-codeblocks, onboarding-gate,
|
|
103
|
-
* persona-governance, php-coding, provider-lifecycle-discipline,
|
|
104
|
-
* roadmap-ci-steps-policy, roadmap-progress-sync, settings-ask-protocol.
|
|
105
|
-
*
|
|
106
|
-
* They do NOT reach the model at no scope: every non-path route
|
|
107
|
-
* (keyword / phrase / command) still delivers the body through the concern, and
|
|
108
|
-
* on `claude-code` they never had a separate host-native path route to lose —
|
|
109
|
-
* `_claude_paths_plan` emits no `paths:` for a mixed-trigger rule on purpose, so
|
|
110
|
-
* under `eager-all` they loaded UNCONDITIONALLY. What is lost is the difference
|
|
111
|
-
* between unconditional and prompt-triggered: a session that touches a matching
|
|
112
|
-
* file and says nothing that matches gets nothing.
|
|
113
|
-
*
|
|
114
|
-
* The labelled corpus cannot see this and the endpoint says so rather than
|
|
115
|
-
* implying otherwise — `model_rule_injection --endpoints` (b) now publishes the
|
|
116
|
-
* shipped `user_prompt_submit` reach beside the pre-registered reading, and
|
|
117
|
-
* every one of these 18 has at least one prompt-matching positive, so none
|
|
118
|
-
* appears in its "reachable only via a path trigger" column.
|
|
119
|
-
*
|
|
120
|
-
* WHY THIS IS NOT WIDENED TO `some` HERE. Measured: exempting all 18 moves the
|
|
121
|
-
* thin rule layer 23,592 -> 39,921 GPT tok (+16,329, +69 %), which is a budget
|
|
122
|
-
* move of a magnitude no agent may take, and it would erase most of the saving
|
|
123
|
-
* the flip is licensed on. Restoring a path route needs either that exemption
|
|
124
|
-
* under a re-anchored baseline or a `pre_tool_use` binding under a raised slot
|
|
125
|
-
* cap — both owner-reserved, so the closure is tracked rather than taken here.
|
|
126
|
-
* ADR-267's Consequences section names the receiver.
|
|
127
|
-
*/
|
|
128
|
-
/**
|
|
129
|
-
* ONE spelling of the router-derived sets, shared with the injector (R2
|
|
130
|
-
* finding 11).
|
|
131
|
-
*
|
|
132
|
-
* `path_only_ids` and `no_trigger_ids` were each a second, hand-rolled
|
|
133
|
-
* implementation of `_lib/rule_injection.ts::pathOnlyRuleIds` /
|
|
134
|
-
* `triggerlessRuleIds` — verified identical over the current router at the time
|
|
135
|
-
* (symmetric difference empty), so drift risk rather than a live defect. It is
|
|
136
|
-
* exactly the hazard `THIN_ENTRY_MARKER`'s own comment argues against one
|
|
137
|
-
* screen below ("a gate that re-spelled this string would drift from the writer
|
|
138
|
-
* silently"), and the two consumers here are the PROJECTOR's exemption set and
|
|
139
|
-
* the INJECTOR's reachability set: they must not be able to disagree about which
|
|
140
|
-
* rules the delivery path can reach.
|
|
141
|
-
*
|
|
142
|
-
* The finding named `path_only_ids`. The defect-pattern sweep found the SECOND
|
|
143
|
-
* instance one function down — `no_trigger_ids` against `triggerlessRuleIds` —
|
|
144
|
-
* and it is delegated in the same change. Count: 2 of 2 duplicated
|
|
145
|
-
* router-derived sets in this file, 0 remaining.
|
|
146
|
-
*/
|
|
147
|
-
function _router() {
|
|
148
|
-
return JSON.parse(fs.readFileSync(ROUTER, 'utf-8'));
|
|
149
|
-
}
|
|
150
|
-
export function path_only_ids() {
|
|
151
|
-
return pathOnlyRuleIds(_router());
|
|
152
|
-
}
|
|
153
|
-
export function no_trigger_ids() {
|
|
154
|
-
return new Set(triggerlessRuleIds(_router()));
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* id → workspaces for every non-kernel router entry (router.json schema v2,
|
|
158
|
-
* road-to-request-scoped-rule-load Phase 1). Rules absent from the map (or
|
|
159
|
-
* with an empty list) fail safe: they stay in scope.
|
|
160
|
-
*/
|
|
161
|
-
export function rule_workspaces_map() {
|
|
162
|
-
const data = JSON.parse(fs.readFileSync(ROUTER, 'utf-8'));
|
|
163
|
-
const map = new Map();
|
|
164
|
-
for (const tier of ['tier_1', 'tier_2']) {
|
|
165
|
-
const entries = data[tier];
|
|
166
|
-
if (!Array.isArray(entries))
|
|
167
|
-
continue;
|
|
168
|
-
for (const e of entries) {
|
|
169
|
-
const obj = e;
|
|
170
|
-
const ws = Array.isArray(obj.workspaces) ? obj.workspaces.map((w) => String(w)) : [];
|
|
171
|
-
map.set(String(obj.id), ws);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return map;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Whether a rule id survives a workspace scope. Kernel always survives;
|
|
178
|
-
* `scope === null` = legacy-all. An out-of-scope non-kernel rule is dropped
|
|
179
|
-
* entirely — neither body nor pointer line (the pointer floor shrinks with
|
|
180
|
-
* consumer scoping).
|
|
181
|
-
*/
|
|
182
|
-
export function id_in_scope(rule_id, scope, kernel, wsMap, fallback_ws = []) {
|
|
183
|
-
if (scope === null || kernel.has(rule_id)) {
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
// Router map first (schema v2); `type: manual` rules are reference-only
|
|
187
|
-
// and never emitted to the router — their frontmatter is the fallback.
|
|
188
|
-
const ws = wsMap.get(rule_id) ?? fallback_ws;
|
|
189
|
-
if (ws.length === 0) {
|
|
190
|
-
return true; // untagged / unknown → fail safe
|
|
191
|
-
}
|
|
192
|
-
return ws.some((w) => scope.includes(w));
|
|
193
|
-
}
|
|
194
|
-
/** `workspaces:` list parsed straight from a rule file's frontmatter. */
|
|
195
|
-
export function fm_workspaces(text) {
|
|
196
|
-
const [fm] = split_frontmatter(text);
|
|
197
|
-
// Flow style: `workspaces: [a, b, c]`
|
|
198
|
-
const flow = /^workspaces:[ \t]*\[([^\]]*)\]/m.exec(fm);
|
|
199
|
-
if (flow) {
|
|
200
|
-
return flow[1]
|
|
201
|
-
.split(',')
|
|
202
|
-
.map((s) => s.trim().replace(/^["']|["']$/g, ''))
|
|
203
|
-
.filter((s) => s.length > 0);
|
|
204
|
-
}
|
|
205
|
-
// Block style; tolerate the list being the LAST frontmatter key.
|
|
206
|
-
const m = /^workspaces:[ \t]*\n((?:[ \t]+-[ \t]+.*(?:\n|$))+)/m.exec(fm);
|
|
207
|
-
if (!m) {
|
|
208
|
-
return [];
|
|
209
|
-
}
|
|
210
|
-
return [...m[1].matchAll(/-[ \t]+(\S+)/g)].map((x) => x[1]);
|
|
211
|
-
}
|
|
212
|
-
/** Return [frontmatter_including_fences, body]. Empty fm if none. */
|
|
213
|
-
export function split_frontmatter(text) {
|
|
214
|
-
if (text.startsWith('---\n')) {
|
|
215
|
-
const end = text.indexOf('\n---\n', 4);
|
|
216
|
-
if (end !== -1) {
|
|
217
|
-
return [text.slice(0, end + 5), text.slice(end + 5)];
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return ['', text];
|
|
221
|
-
}
|
|
222
|
-
function _description(fm) {
|
|
223
|
-
// re.search(r'^description:\s*"?(.+?)"?\s*$', fm, re.MULTILINE)
|
|
224
|
-
const m = /^description:\s*"?(.+?)"?\s*$/m.exec(fm);
|
|
225
|
-
return m ? m[1].trim() : '';
|
|
226
|
-
}
|
|
227
|
-
// How many trigger keywords/phrases to surface as the always-on match hint.
|
|
228
|
-
const _TRIGGER_HINT_LIMIT = 6;
|
|
229
|
-
/** A short, comma-joined sample of the rule's trigger keywords/phrases. */
|
|
230
|
-
function _trigger_hint(fm) {
|
|
231
|
-
const hits = [];
|
|
232
|
-
// re.finditer(r'^\s*-\s*(?:keyword|phrase):\s*"?(.+?)"?\s*$', fm, re.MULTILINE)
|
|
233
|
-
const re = /^\s*-\s*(?:keyword|phrase):\s*"?(.+?)"?\s*$/gm;
|
|
234
|
-
let m;
|
|
235
|
-
while ((m = re.exec(fm)) !== null) {
|
|
236
|
-
hits.push(m[1].trim());
|
|
237
|
-
if (hits.length >= _TRIGGER_HINT_LIMIT) {
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return hits.join(', ');
|
|
242
|
-
}
|
|
243
|
-
/** Python `str.title()` — uppercase first alpha of each run, rest lowercase. */
|
|
244
|
-
function _title(s) {
|
|
245
|
-
return s.replace(/[A-Za-z]+/g, (w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase());
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* The marker that makes a projected entry recognisable as a stub.
|
|
249
|
-
*
|
|
250
|
-
* Exported so the WRITER and every DETECTOR share one definition. A gate that
|
|
251
|
-
* re-spelled this string would drift from the writer silently, and the failure
|
|
252
|
-
* would be invisible in exactly the direction that matters: a stub the gate
|
|
253
|
-
* fails to recognise reads as a complete rule body.
|
|
254
|
-
*/
|
|
255
|
-
export const THIN_ENTRY_MARKER = '> Routed rule — load the body on trigger-match.';
|
|
256
|
-
/** Is this projected entry a pointer stub rather than a rule body? */
|
|
257
|
-
export function is_thin_entry(text) {
|
|
258
|
-
return text.includes(THIN_ENTRY_MARKER);
|
|
259
|
-
}
|
|
260
37
|
/**
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* FIXED 2026-09-07: this pointed into the uncondensed source tree ADR-051
|
|
264
|
-
* retired — the literal path is deliberately NOT reproduced here, because
|
|
265
|
-
* `check_no_uncondensed_refs` matches the string and cannot tell a repair
|
|
266
|
-
* record from a live reference; `git log -S` on this file finds the old value.
|
|
267
|
-
* It exists in no checkout, so EVERY stub's fallback pointer
|
|
268
|
-
* resolved to nothing — invisible under `delivery`, where the hook loads the
|
|
269
|
-
* body from `dist/agent-src/rules` and never follows this link, and total under
|
|
270
|
-
* `thin`, where the pointer is the only path to the body there is.
|
|
38
|
+
* The mechanism lives in `_lib/thin_rules.ts`; this file is its CLI.
|
|
271
39
|
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
* needs an operator to have added `cline` to that list, and its pointer is off
|
|
278
|
-
* by one level. That is strictly better than the previous state, where the
|
|
279
|
-
* pointer was dead in all three, and it is recorded here so the remaining case
|
|
280
|
-
* is a known limit rather than a surprise.
|
|
40
|
+
* Re-exported wholesale so every existing importer of
|
|
41
|
+
* `project_thin_rules.{build_thin,thin_entry,is_thin_entry,RULES_SOURCE,…}`
|
|
42
|
+
* keeps working unchanged. The split exists because `src/scripts/install.ts` is
|
|
43
|
+
* a bundle entry and `check_installer_import_purity` forbids it reaching a
|
|
44
|
+
* module-level `process.exit()` — which this file has, at its foot, by design.
|
|
281
45
|
*/
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const desc = _description(fm);
|
|
287
|
-
const hint = _trigger_hint(fm);
|
|
288
|
-
const title = _title(rule_id.replace(/-/g, ' '));
|
|
289
|
-
const fires = hint ? ` Fires on: ${hint}.` : '';
|
|
290
|
-
return (`## ${title}\n` +
|
|
291
|
-
`${THIN_ENTRY_MARKER}${fires} ${desc} ` +
|
|
292
|
-
`Body: [\`${rule_id}\`](${BODY_LINK_PREFIX}${rule_id}.md)\n`);
|
|
293
|
-
}
|
|
294
|
-
/** Map {filename: thin_or_full_text} for every rule. Kernel stays full. */
|
|
295
|
-
export function build_thin(rules_dir = RULES_SOURCE, scope = null,
|
|
296
|
-
/**
|
|
297
|
-
* Optional sink for the D3 diagnostic
|
|
298
|
-
* (road-to-delivery-for-every-host 2.2).
|
|
299
|
-
*
|
|
300
|
-
* An `auto` rule the router gives NO trigger is already kept full-bodied by
|
|
301
|
-
* `noTrigger` below, which is the substantive protection and predates this
|
|
302
|
-
* roadmap. What did not exist is any way to SEE it happen: the rule is
|
|
303
|
-
* silently exempted, so an author who removes a rule's last trigger gets a
|
|
304
|
-
* silently eager rule and no signal. The line makes the exemption audible.
|
|
305
|
-
*/
|
|
306
|
-
announce = null) {
|
|
307
|
-
const kernel = kernel_ids();
|
|
308
|
-
const noTrigger = no_trigger_ids();
|
|
309
|
-
const pathOnly = path_only_ids();
|
|
310
|
-
const wsMap = scope !== null ? rule_workspaces_map() : new Map();
|
|
311
|
-
const out = new Map();
|
|
312
|
-
for (const p of _globSortedMd(rules_dir)) {
|
|
313
|
-
const text = fs.readFileSync(p, 'utf-8');
|
|
314
|
-
const stem = path.basename(p).replace(/\.md$/, '');
|
|
315
|
-
if (!id_in_scope(stem, scope, kernel, wsMap, fm_workspaces(text))) {
|
|
316
|
-
continue; // out of workspace scope — no body, no pointer line
|
|
317
|
-
}
|
|
318
|
-
const full = kernel.has(stem) || noTrigger.has(stem) || pathOnly.has(stem);
|
|
319
|
-
if (announce !== null && noTrigger.has(stem) && !kernel.has(stem)) {
|
|
320
|
-
announce(`D3: trigger-less auto rule ${path.basename(p)} — kept full-bodied, never thinned`);
|
|
321
|
-
}
|
|
322
|
-
if (announce !== null && pathOnly.has(stem) && !kernel.has(stem) && !noTrigger.has(stem)) {
|
|
323
|
-
announce(`E2: path-only auto rule ${path.basename(p)} — kept full-bodied; its only triggers ` +
|
|
324
|
-
`are path-shaped and the delivery concern is not bound on pre_tool_use`);
|
|
325
|
-
}
|
|
326
|
-
out.set(path.basename(p), full ? text : thin_entry(stem, text));
|
|
327
|
-
}
|
|
328
|
-
return out;
|
|
329
|
-
}
|
|
46
|
+
export * from './_lib/thin_rules.js';
|
|
47
|
+
import { _globSortedMd, build_thin, fm_workspaces, id_in_scope, kernel_ids, no_trigger_ids, REPO_ROOT, RULES_SOURCE, rule_workspaces_map, } from './_lib/thin_rules.js';
|
|
48
|
+
void REPO_ROOT;
|
|
49
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
330
50
|
/** Python `round(x, 1)` — round-half-to-even at one decimal. */
|
|
331
51
|
function _python_round1(x) {
|
|
332
52
|
const scaled = x * 10;
|
|
@@ -190,6 +190,9 @@ export const settingsSchema = z.object({
|
|
|
190
190
|
fidelity_mode: 'strict',
|
|
191
191
|
approximation: { enabled: false, tolerance: { color: null, length: null } },
|
|
192
192
|
}),
|
|
193
|
+
code_graph: z.object({
|
|
194
|
+
consumer_index_paths: z.array(z.string()).default([]).describe("Extra project-relative paths where THIS project keeps a code-graph index another tool wrote. The built-in list is deliberately vendor-neutral (graph.json, code-graph.json, .code-graph/graph.json) and names no tool, so a tool that writes its index elsewhere is named here rather than waited for. A graph found this way LOADS and answers query and explain with every edge tagged read-from-elsewhere; the gate verbs (impact, untested, dead) refuse a graph made only of such edges and say so, because an empty answer from a gate must not read as 'nothing found' when it means 'nothing trusted'. Absolute paths and paths escaping the project root are ignored."),
|
|
195
|
+
}).default({}),
|
|
193
196
|
consistency: z.object({
|
|
194
197
|
cross_source: crossSourceMode.default('on').describe('Consumed by the cross-source-consistency rule. When the agent works from multiple sources (ticket text, an attached image/mockup, the spec, the codebase) it checks them against each other and asks before proceeding on a discrepancy — instead of silently guessing. on (default) = surface every real cross-source contradiction / silent-scope-expansion as one question; auto = surface only high-confidence contradictions, state low-confidence as an assumption; off = no cross-source checking.'),
|
|
195
198
|
}).default({ cross_source: 'on' }),
|
|
@@ -319,6 +322,9 @@ export const settingsSchema = z.object({
|
|
|
319
322
|
tier1_concerns: z.array(z.string()).default([]).describe('Concern IDs (one per line) that are allowed to block the run on failure rather than warn. Reserved for high-confidence guards — leave empty unless you maintain custom hooks.'),
|
|
320
323
|
hard_fail: z.boolean().default(false).describe('When a hook exceeds hooks.concern_budget.max_per_event, fail the run (true) instead of warning and continuing (false, default). Turn on in CI when you want hook quality to gate merges.'),
|
|
321
324
|
}),
|
|
325
|
+
verify_before_complete: z.object({
|
|
326
|
+
touched_file_quality: z.enum(['off', 'shadow', 'warn']).default('off').describe("Stop-slot pass that runs the project's OWN quality commands — the ones resolve_toolchain() already reports — over the files this turn edited. Default off. `shadow` records a per-run result and emits nothing; `warn` adds ONE advisory line of at most 200 bytes. Never blocks and never counts as verification: a command recorded here never reaches _lib/verification_command.ts, so a clean eslint run cannot let a turn claim it verified anything. A writing command runs only in its check form (pint --test) or not at all, and a command with no per-file form is skipped rather than run project-wide at every stop."),
|
|
327
|
+
}).default({}),
|
|
322
328
|
injection_scan: z.object({
|
|
323
329
|
enabled: z.boolean().default(false).describe('PostToolUse prompt-injection scanner (road-to-security-pillar.md P3.2). Default off. When on, scans tool output (file reads, web fetches, MCP responses) for injection signatures and WARNS in context (never blocks). Runtime backstop on top of the always-on untrusted-input-defense rule; detection is probabilistic.'),
|
|
324
330
|
}).default({}),
|
|
@@ -24,10 +24,13 @@
|
|
|
24
24
|
* `score_skill_relevance` CLI's argparse-parity suite is the check that the move
|
|
25
25
|
* changed nothing.
|
|
26
26
|
*
|
|
27
|
-
* THE
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
27
|
+
* THE ADDITIONS ARE ALL OFF BY DEFAULT and live in one {@link RankOptions}
|
|
28
|
+
* object: three that widen the indexed TERM SOURCE (trigger prose, the skill's
|
|
29
|
+
* own `## When to use` section, the body's headings) and one that changes the
|
|
30
|
+
* WEIGHTING (inverse document frequency over the catalogue). They are opt-in
|
|
31
|
+
* parameters rather than separate functions so two configurations can be
|
|
32
|
+
* measured against each other on one corpus without becoming two rankers. With
|
|
33
|
+
* every flag off the arithmetic is the ported one, unchanged.
|
|
31
34
|
*
|
|
32
35
|
* Pure — no imports, no I/O, no clock.
|
|
33
36
|
*/
|
|
@@ -113,23 +116,78 @@ export function skillTerms(skill, opts = {}) {
|
|
|
113
116
|
const parts = [skill.name, skill.description];
|
|
114
117
|
if (opts.includeTriggers && skill.triggerText)
|
|
115
118
|
parts.push(...skill.triggerText);
|
|
119
|
+
if (opts.includeWhenToUse && skill.whenToUseText)
|
|
120
|
+
parts.push(skill.whenToUseText);
|
|
121
|
+
if (opts.includeHeadings && skill.headingText)
|
|
122
|
+
parts.push(...skill.headingText);
|
|
116
123
|
return tokenize(parts.join(' '));
|
|
117
124
|
}
|
|
125
|
+
/** True when `opts` turns on at least one term source beyond name + description. */
|
|
126
|
+
export function widensTermSource(opts) {
|
|
127
|
+
return Boolean(opts.includeTriggers || opts.includeWhenToUse || opts.includeHeadings);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @param termSets the per-skill term sets, in the same order as `skills`.
|
|
131
|
+
* Required rather than derived, so the catalogue is tokenized ONCE per call
|
|
132
|
+
* instead of once here and again at the scoring loop. Tokenizing ~300 skills
|
|
133
|
+
* twice per prompt is invisible next to re-reading them from disk, which is
|
|
134
|
+
* exactly why it would have stayed invisible.
|
|
135
|
+
*/
|
|
136
|
+
export function buildTermStats(skills, termSets) {
|
|
137
|
+
const df = new Map();
|
|
138
|
+
for (const terms of termSets) {
|
|
139
|
+
for (const t of terms)
|
|
140
|
+
df.set(t, (df.get(t) ?? 0) + 1);
|
|
141
|
+
}
|
|
142
|
+
return { df, skills: skills.length };
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The weight one matched term carries.
|
|
146
|
+
*
|
|
147
|
+
* `ln(1 + skills / (1 + df))`, the smoothed textbook form: a term on every
|
|
148
|
+
* skill tends to zero, a term on one skill carries the most. Unknown terms are
|
|
149
|
+
* treated as df 0 — a task term no skill indexes cannot be matched anyway, so
|
|
150
|
+
* its weight only affects the denominator, where counting it fully is right:
|
|
151
|
+
* failing to cover a rare term should cost more than failing to cover a common
|
|
152
|
+
* one.
|
|
153
|
+
*/
|
|
154
|
+
export function idf(term, stats) {
|
|
155
|
+
return Math.log(1 + stats.skills / (1 + (stats.df.get(term) ?? 0)));
|
|
156
|
+
}
|
|
118
157
|
/**
|
|
119
158
|
* The score. `taskTerms` is `tokenize(task)`; `terms` is `skillTerms(skill)`.
|
|
120
159
|
*
|
|
121
160
|
* Both are passed in rather than derived here so a caller ranking N skills
|
|
122
161
|
* tokenizes the task once and each skill once, which is what makes this usable
|
|
123
|
-
* on a per-prompt hook path.
|
|
162
|
+
* on a per-prompt hook path. `opts` and `stats` are optional and, with them
|
|
163
|
+
* absent or every flag off, the arithmetic is exactly the Python-parity one.
|
|
124
164
|
*/
|
|
125
|
-
export function scoreSkill(taskTerms, skill, terms) {
|
|
165
|
+
export function scoreSkill(taskTerms, skill, terms, opts = {}, stats) {
|
|
166
|
+
if (opts.idfWeighting && !stats) {
|
|
167
|
+
throw new Error('scoreSkill: idfWeighting is set but no TermStats was passed — scoring unweighted here ' +
|
|
168
|
+
'would publish a baseline number under the idf label. Build stats with buildTermStats.');
|
|
169
|
+
}
|
|
126
170
|
if (taskTerms.size === 0)
|
|
127
171
|
return 0;
|
|
128
|
-
let
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
172
|
+
let overlap;
|
|
173
|
+
if (opts.idfWeighting && stats) {
|
|
174
|
+
let hit = 0;
|
|
175
|
+
let total = 0;
|
|
176
|
+
for (const t of taskTerms) {
|
|
177
|
+
const w = idf(t, stats);
|
|
178
|
+
total += w;
|
|
179
|
+
if (terms.has(t))
|
|
180
|
+
hit += w;
|
|
181
|
+
}
|
|
182
|
+
overlap = total > 0 ? hit / total : 0;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
let inter = 0;
|
|
186
|
+
for (const t of taskTerms)
|
|
187
|
+
if (terms.has(t))
|
|
188
|
+
inter++;
|
|
189
|
+
overlap = inter / Math.max(taskTerms.size, 1);
|
|
190
|
+
}
|
|
133
191
|
let personaHit = 0;
|
|
134
192
|
const taskLower = [...taskTerms].join(' ');
|
|
135
193
|
for (const persona of skill.personas ?? []) {
|
|
@@ -147,9 +205,12 @@ export function scoreSkill(taskTerms, skill, terms) {
|
|
|
147
205
|
*/
|
|
148
206
|
export function rankSkills(task, skills, opts = {}) {
|
|
149
207
|
const taskTerms = tokenize(task);
|
|
208
|
+
const termSets = skills.map((s) => skillTerms(s, opts));
|
|
209
|
+
const stats = opts.idfWeighting ? buildTermStats(skills, termSets) : undefined;
|
|
150
210
|
const rows = [];
|
|
151
|
-
for (
|
|
152
|
-
const
|
|
211
|
+
for (let i = 0; i < skills.length; i += 1) {
|
|
212
|
+
const skill = skills[i];
|
|
213
|
+
const score = scoreSkill(taskTerms, skill, termSets[i], opts, stats);
|
|
153
214
|
if (score > 0)
|
|
154
215
|
rows.push({ name: skill.name, score, personas: [...(skill.personas ?? [])] });
|
|
155
216
|
}
|
|
@@ -247,8 +247,8 @@ dispatch runs, not WHETHER the layer exists, so they keep their own C rows.
|
|
|
247
247
|
|---|---|
|
|
248
248
|
| A — preference | 26 |
|
|
249
249
|
| B — consent | 3 |
|
|
250
|
-
| C — guarded |
|
|
251
|
-
| **Total** | **
|
|
250
|
+
| C — guarded | 126 |
|
|
251
|
+
| **Total** | **155** |
|
|
252
252
|
|
|
253
253
|
It rose again on 2026-09-13 when `road-to-adversarial-verification-and-long-runs`
|
|
254
254
|
Phase 0 added three C keys: `quality.local_auto_run_in_mission` (`consent` — it
|
|
@@ -381,10 +381,10 @@ the template, which is the drift this contract exists to prevent.
|
|
|
381
381
|
| Disposition | Keys |
|
|
382
382
|
|---|---|
|
|
383
383
|
| derivable | 83 |
|
|
384
|
-
| un-inferrable |
|
|
385
|
-
| consent |
|
|
384
|
+
| un-inferrable | 10 |
|
|
385
|
+
| consent | 48 |
|
|
386
386
|
| policy | 14 |
|
|
387
|
-
| **Total** | **
|
|
387
|
+
| **Total** | **155** |
|
|
388
388
|
|
|
389
389
|
First measured 2026-08-12 at 140 leaves (derivable 88 · consent 38 ·
|
|
390
390
|
un-inferrable 9 · policy 5), from the table below rather than predicted — the
|
|
@@ -562,6 +562,7 @@ Rows follow template order, so a diff against the template reads straight down.
|
|
|
562
562
|
| `design.approximation.tolerance.color` | C | `null` | decides which colour deviations may be taken silently | policy |
|
|
563
563
|
| `design.approximation.tolerance.length` | C | `null` | decides which length deviations may be taken silently | policy |
|
|
564
564
|
| `consistency.cross_source` | C | `"on"` | disables the cross-source discrepancy gate | derivable — the rule's own trigger condition; a discrepancy exists only when two present sources contradict |
|
|
565
|
+
| `code_graph.consumer_index_paths` | C | `[]` | names where this project's OTHER tool writes a code-graph index, so it widens what the graph reader will load and trust | un-inferrable — the path belongs to a tool this package does not ship and cannot probe for; the built-in list is deliberately vendor-neutral, so only the operator knows where their index lands |
|
|
565
566
|
| `screenshots.identity_allowlist` | C | `[]` | allowlist of identities that ship unredacted | consent |
|
|
566
567
|
| `screenshots.forbid_terminal_capture` | C | `true` | kill-switch over the highest-leak capture path | consent |
|
|
567
568
|
| `screenshots.data_bearing_gate` | C | `"on"` | the human-confirmation gate over a published egress | consent |
|
|
@@ -622,6 +623,7 @@ Rows follow template order, so a diff against the template reads straight down.
|
|
|
622
623
|
| `hooks.design_pass.enabled` | C | `false` | C-test 1 — it configures code that runs on every tool call and at every turn end, and unlike its two `hooks.*` neighbours its stop pass can BLOCK rather than warn | policy — whether an operator accepts a gate that can refuse a turn is a risk preference, not a fact the tree can compute. The two neighbours are `derivable` because they only ever warn; the block is the discriminator. `road-to-frontend-power` transfers the default flip to the owner for the same reason |
|
|
623
624
|
| `hooks.code_graph.enabled` | C | `false` | INERT since 2026-09-07 — the nudge it gated was replaced by `code-graph-context`, which reads no flag. The KEY stays registered because `docs/MIGRATION.md` commits to exactly that ("the surfaces stay registered and disabled"): removing it is a breaking change for any consumer who set it, and the row was briefly marked REMOVED, which left the template's own leaf unclassified. Classified, not deleted. | derivable — the index-detection probe the replacement hook already runs; no index means silence |
|
|
624
625
|
| `hooks.suggestion_capture.enabled` | C | `false` | configures code that runs at every turn end and every prompt | consent |
|
|
626
|
+
| `hooks.verify_before_complete.touched_file_quality` | C | `"off"` | C-test 1 — it decides whether the stop hook SPAWNS the project's own quality commands over the turn's edited files, so the cost it authorises is other people's processes on the operator's machine | consent — running a consumer's toolchain against their working tree is a thing to be permitted, not a fact the tree can derive. The three values are not a severity ladder the agent may climb: `shadow` records, `warn` adds one advisory line, and the flip from one to the other is the owner decision `road-to-touched-files-that-pass-their-own-tools` 2.3 defers |
|
|
625
627
|
| `decision_engine.surface_traces` | C | `false` | the decision engine’s own black box; the agent must not be able to close it | derivable — the engine's own active-gate state; there is nothing to surface when no gate fired |
|
|
626
628
|
| `decision_engine.min_confidence` | C | `"off"` | the confidence gate | derivable — the confidence band the scoring engine already computes at the plan phase |
|
|
627
629
|
| `decision_engine.block_on_risk` | C | `"off"` | the risk-class gate | derivable — the risk class the engine already computes at the implement phase; the Hard Floor covers the irreversible end unconditionally |
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event4u/agent-config",
|
|
3
3
|
"mcpName": "io.github.event4u-app/agent-config",
|
|
4
|
-
"version": "16.
|
|
4
|
+
"version": "16.3.0",
|
|
5
5
|
"description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) — every claim machine-checked, including the counts in these badges.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"private": false,
|