@event4u/agent-config 16.1.0 → 16.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +98 -257
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +5 -5
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1862 -809
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +132 -80
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +7972 -5186
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2226 -1055
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +40913 -34865
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +29 -0
- package/dist/shared/skillRanking.js +74 -13
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/contracts/settings-classes.md +10 -6
- package/package.json +4 -4
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +91 -22
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +327 -3
- package/src/config/gate-violation-baselines.json +21 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +8 -3
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +38 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +28 -90
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +600 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +573 -25
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +621 -22
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +138 -7
- package/src/scripts/check_generator_sync.ts +71 -0
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +89 -9
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +90 -14
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +192 -14
- package/src/scripts/hooks/block_config_weakening.ts +294 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +100 -9
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +77 -71
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +1 -2
- package/src/scripts/hooks/exit_codes.ts +129 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +146 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +765 -68
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +70 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +75 -189
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +108 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +7 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +421 -17
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -7
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +41 -0
- package/src/shared/skillRanking.ts +117 -11
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
- package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Which one-token keyword triggers fire on prompts that belong to other rules.
|
|
4
|
+
*
|
|
5
|
+
* Step 1.3 of `road-to-rule-triggers-and-links-that-hold`. A single common word
|
|
6
|
+
* — `rename`, `delete` — is a legitimate trigger for the rule that owns the
|
|
7
|
+
* subject and a standing cost for every prompt that merely uses the word. This
|
|
8
|
+
* reports which words sit at which share of the corpus. **Report only.** A
|
|
9
|
+
* trigger change is a separate decision per rule, because a common word can be
|
|
10
|
+
* exactly right: `augment-edit-discipline` genuinely wants to fire on a rename.
|
|
11
|
+
*
|
|
12
|
+
* The corpus is `tests/eval/routing-matrix/*.yaml`, the frozen set this tree
|
|
13
|
+
* already evaluates routing against. Each `positives[].prompt` is labelled with
|
|
14
|
+
* its file's rule. For a one-token keyword `K` on rule `R`, the share is:
|
|
15
|
+
*
|
|
16
|
+
* |{ prompt : label(prompt) != R and K occurs as a word }|
|
|
17
|
+
* ---------------------------------------------------------
|
|
18
|
+
* |{ prompt : label(prompt) != R }|
|
|
19
|
+
*
|
|
20
|
+
* `near_misses` are deliberately NOT in the denominator. They carry a negative
|
|
21
|
+
* label against their own file's rule and no positive label against any other,
|
|
22
|
+
* so counting them would mix "belongs to another rule" with "belongs to no
|
|
23
|
+
* rule" — two different claims, and only the first is what a cross-firing
|
|
24
|
+
* trigger costs.
|
|
25
|
+
*
|
|
26
|
+
* The 5 % threshold is a stated default for a report, not a gate (D3). Nothing
|
|
27
|
+
* acts on the figure automatically.
|
|
28
|
+
*/
|
|
29
|
+
import * as fs from 'node:fs';
|
|
30
|
+
import * as path from 'node:path';
|
|
31
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
32
|
+
|
|
33
|
+
import { parse as parseYaml } from 'yaml';
|
|
34
|
+
|
|
35
|
+
// ledger-exempt: a REPORTER, not a gate. Its only non-zero exit says the
|
|
36
|
+
// corpus or the rule directory could not be read.
|
|
37
|
+
|
|
38
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
39
|
+
|
|
40
|
+
export const DEFAULT_THRESHOLD = 0.05;
|
|
41
|
+
|
|
42
|
+
export interface LabelledPrompt {
|
|
43
|
+
rule: string;
|
|
44
|
+
prompt: string;
|
|
45
|
+
/** `positive` — belongs to `rule`. `near_miss` — declared NOT to be `rule`. */
|
|
46
|
+
kind: 'positive' | 'near_miss';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface TriggerRow {
|
|
50
|
+
rule: string;
|
|
51
|
+
keyword: string;
|
|
52
|
+
/** Foreign POSITIVE prompts the keyword occurs in. */
|
|
53
|
+
hits: number;
|
|
54
|
+
/** Prompts labelled positive against any other rule. */
|
|
55
|
+
foreign: number;
|
|
56
|
+
share: number;
|
|
57
|
+
/**
|
|
58
|
+
* Occurrences in a near-miss the rule ITSELF declares — the keyword fires
|
|
59
|
+
* on a prompt that rule's own fixture says it must not fire on. A declared
|
|
60
|
+
* false positive, and the sharpest row this report can produce.
|
|
61
|
+
*/
|
|
62
|
+
own_near_miss_hits: number;
|
|
63
|
+
own_near_misses: number;
|
|
64
|
+
/** Occurrences in another rule's near-miss list. */
|
|
65
|
+
foreign_near_miss_hits: number;
|
|
66
|
+
/** Which rules those foreign positives belong to, highest first. */
|
|
67
|
+
top_labels: { rule: string; count: number }[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Every prompt in the matrix, labelled with its file's rule and its kind. */
|
|
71
|
+
export function loadCorpus(matrixDir: string): LabelledPrompt[] {
|
|
72
|
+
const out: LabelledPrompt[] = [];
|
|
73
|
+
const files = fs
|
|
74
|
+
.readdirSync(matrixDir)
|
|
75
|
+
.filter((n) => n.endsWith('.yaml'))
|
|
76
|
+
.sort();
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const doc = parseYaml(fs.readFileSync(path.join(matrixDir, file), 'utf-8')) as {
|
|
79
|
+
rule?: unknown;
|
|
80
|
+
positives?: { prompt?: unknown }[];
|
|
81
|
+
near_misses?: { prompt?: unknown }[];
|
|
82
|
+
} | null;
|
|
83
|
+
const rule = typeof doc?.rule === 'string' ? doc.rule : '';
|
|
84
|
+
if (!rule) continue;
|
|
85
|
+
for (const [items, kind] of [
|
|
86
|
+
[doc?.positives, 'positive'],
|
|
87
|
+
[doc?.near_misses, 'near_miss'],
|
|
88
|
+
] as const) {
|
|
89
|
+
if (!Array.isArray(items)) continue;
|
|
90
|
+
for (const item of items) {
|
|
91
|
+
if (typeof item?.prompt === 'string' && item.prompt.trim()) {
|
|
92
|
+
out.push({ rule, prompt: item.prompt, kind });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** One-token keyword triggers per rule, from `src/rules/*.md` frontmatter. */
|
|
101
|
+
export function singleTokenKeywords(rulesDir: string): { rule: string; keyword: string }[] {
|
|
102
|
+
const out: { rule: string; keyword: string }[] = [];
|
|
103
|
+
const files = fs
|
|
104
|
+
.readdirSync(rulesDir)
|
|
105
|
+
.filter((n) => n.endsWith('.md'))
|
|
106
|
+
.sort();
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
const content = fs.readFileSync(path.join(rulesDir, file), 'utf-8');
|
|
109
|
+
if (!content.startsWith('---')) continue;
|
|
110
|
+
const end = content.indexOf('\n---', 3);
|
|
111
|
+
const block = end === -1 ? content : content.slice(0, end);
|
|
112
|
+
const rule = file.replace(/\.md$/, '');
|
|
113
|
+
for (const m of block.matchAll(/^\s*-\s*keyword:\s*["']?([^"'\n]+?)["']?\s*$/gm)) {
|
|
114
|
+
const kw = (m[1] as string).trim();
|
|
115
|
+
if (kw === '' || /\s/.test(kw)) continue;
|
|
116
|
+
out.push({ rule, keyword: kw });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Word-boundary, case-insensitive, with the keyword's own characters escaped. */
|
|
123
|
+
function occursAsWord(prompt: string, keyword: string): boolean {
|
|
124
|
+
const esc = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
125
|
+
return new RegExp(`(?:^|[^\\p{L}\\p{N}_])${esc}(?:$|[^\\p{L}\\p{N}_])`, 'iu').test(prompt);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function rows(
|
|
129
|
+
corpus: readonly LabelledPrompt[],
|
|
130
|
+
keywords: readonly { rule: string; keyword: string }[],
|
|
131
|
+
): TriggerRow[] {
|
|
132
|
+
const out: TriggerRow[] = [];
|
|
133
|
+
for (const { rule, keyword } of keywords) {
|
|
134
|
+
const foreign = corpus.filter((c) => c.rule !== rule && c.kind === 'positive');
|
|
135
|
+
if (foreign.length === 0) continue;
|
|
136
|
+
const hitting = foreign.filter((c) => occursAsWord(c.prompt, keyword));
|
|
137
|
+
const ownNear = corpus.filter((c) => c.rule === rule && c.kind === 'near_miss');
|
|
138
|
+
const foreignNear = corpus.filter((c) => c.rule !== rule && c.kind === 'near_miss');
|
|
139
|
+
const labels = new Map<string, number>();
|
|
140
|
+
for (const h of hitting) labels.set(h.rule, (labels.get(h.rule) ?? 0) + 1);
|
|
141
|
+
out.push({
|
|
142
|
+
rule,
|
|
143
|
+
keyword,
|
|
144
|
+
hits: hitting.length,
|
|
145
|
+
foreign: foreign.length,
|
|
146
|
+
share: hitting.length / foreign.length,
|
|
147
|
+
own_near_miss_hits: ownNear.filter((c) => occursAsWord(c.prompt, keyword)).length,
|
|
148
|
+
own_near_misses: ownNear.length,
|
|
149
|
+
foreign_near_miss_hits: foreignNear.filter((c) => occursAsWord(c.prompt, keyword)).length,
|
|
150
|
+
top_labels: [...labels.entries()]
|
|
151
|
+
.map(([r, count]) => ({ rule: r, count }))
|
|
152
|
+
.sort((a, b) => b.count - a.count || a.rule.localeCompare(b.rule))
|
|
153
|
+
.slice(0, 5),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
out.sort(
|
|
157
|
+
(a, b) =>
|
|
158
|
+
b.share - a.share ||
|
|
159
|
+
b.own_near_miss_hits - a.own_near_miss_hits ||
|
|
160
|
+
b.foreign_near_miss_hits - a.foreign_near_miss_hits ||
|
|
161
|
+
a.rule.localeCompare(b.rule) ||
|
|
162
|
+
a.keyword.localeCompare(b.keyword),
|
|
163
|
+
);
|
|
164
|
+
return out;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function renderTable(data: readonly TriggerRow[]): string[] {
|
|
168
|
+
const L: string[] = [];
|
|
169
|
+
L.push(
|
|
170
|
+
'| Rule | Keyword | Foreign positives | Share | Own near-miss hits | Foreign near-miss hits | Mostly labelled against |',
|
|
171
|
+
);
|
|
172
|
+
L.push('|---|---|---:|---:|---:|---:|---|');
|
|
173
|
+
for (const r of data) {
|
|
174
|
+
const labels = r.top_labels.map((l) => `\`${l.rule}\` ${String(l.count)}`).join(', ') || '—';
|
|
175
|
+
L.push(
|
|
176
|
+
`| \`${r.rule}\` | \`${r.keyword}\` | ${String(r.hits)}/${String(r.foreign)} | ` +
|
|
177
|
+
`${(r.share * 100).toFixed(1)} % | ${String(r.own_near_miss_hits)}/${String(r.own_near_misses)} | ` +
|
|
178
|
+
`${String(r.foreign_near_miss_hits)} | ${labels} |`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return L;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const USAGE =
|
|
185
|
+
'usage: report_single_token_triggers [--root DIR] [--threshold F] [--json | --table] [--all]\n' +
|
|
186
|
+
' --threshold share above which a row is reported (default 0.05)\n' +
|
|
187
|
+
' --all report every one-token keyword, not just those over the threshold\n';
|
|
188
|
+
|
|
189
|
+
export function main(): number {
|
|
190
|
+
const argv = process.argv.slice(2);
|
|
191
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
192
|
+
process.stdout.write(USAGE);
|
|
193
|
+
return 0;
|
|
194
|
+
}
|
|
195
|
+
const KNOWN = ['--root', '--threshold', '--json', '--table', '--all'];
|
|
196
|
+
// A silently-ignored `--treshold` would report against a threshold the
|
|
197
|
+
// operator did not ask for, while still printing the default in the header.
|
|
198
|
+
for (const a of argv) {
|
|
199
|
+
if (a.startsWith('-') && !KNOWN.includes(a)) {
|
|
200
|
+
process.stderr.write(`unknown argument: ${a}\n${USAGE}`);
|
|
201
|
+
return 2;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const flagValue = (f: string): string | null => {
|
|
205
|
+
const i = argv.indexOf(f);
|
|
206
|
+
return i >= 0 && i + 1 < argv.length ? (argv[i + 1] as string) : null;
|
|
207
|
+
};
|
|
208
|
+
const root = flagValue('--root') ?? process.cwd();
|
|
209
|
+
const rawT = flagValue('--threshold');
|
|
210
|
+
const threshold = rawT === null ? DEFAULT_THRESHOLD : Number.parseFloat(rawT);
|
|
211
|
+
if (!Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
|
|
212
|
+
process.stderr.write('--threshold must be a fraction between 0 and 1\n');
|
|
213
|
+
return 2;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const matrixDir = path.join(root, 'tests', 'eval', 'routing-matrix');
|
|
217
|
+
const rulesDir = path.join(root, 'src', 'rules');
|
|
218
|
+
if (!fs.existsSync(matrixDir) || !fs.existsSync(rulesDir)) {
|
|
219
|
+
process.stderr.write(`missing ${matrixDir} or ${rulesDir}\n`);
|
|
220
|
+
return 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const corpus = loadCorpus(matrixDir);
|
|
224
|
+
const keywords = singleTokenKeywords(rulesDir);
|
|
225
|
+
const all = rows(corpus, keywords);
|
|
226
|
+
// A keyword reaches the report by EITHER axis: the share the step names, or
|
|
227
|
+
// a hit on a near-miss. Filtering on the share alone would have hidden the
|
|
228
|
+
// only rows this corpus actually produces — see the report's own § on why
|
|
229
|
+
// the 5 % threshold finds nothing here.
|
|
230
|
+
const data = argv.includes('--all')
|
|
231
|
+
? all
|
|
232
|
+
: all.filter((r) => r.share > threshold || r.own_near_miss_hits > 0 || r.foreign_near_miss_hits > 0);
|
|
233
|
+
|
|
234
|
+
if (argv.includes('--json')) {
|
|
235
|
+
process.stdout.write(
|
|
236
|
+
`${JSON.stringify({ threshold, corpus: corpus.length, keywords: keywords.length, rows: data }, null, 2)}\n`,
|
|
237
|
+
);
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
if (argv.includes('--table')) {
|
|
241
|
+
process.stdout.write(`${renderTable(data).join('\n')}\n`);
|
|
242
|
+
return 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const positives = corpus.filter((c) => c.kind === 'positive').length;
|
|
246
|
+
process.stdout.write(
|
|
247
|
+
`corpus ${String(corpus.length)} prompt(s) — ${String(positives)} positive, ` +
|
|
248
|
+
`${String(corpus.length - positives)} near-miss · ` +
|
|
249
|
+
`${String(keywords.length)} one-token keyword(s) over ` +
|
|
250
|
+
`${String(new Set(keywords.map((k) => k.rule)).size)} rule(s)\n` +
|
|
251
|
+
`${String(all.filter((r) => r.share > threshold).length)} row(s) above ` +
|
|
252
|
+
`${(threshold * 100).toFixed(1)} % of foreign positives · ` +
|
|
253
|
+
`${String(data.length)} reportable on either axis\n\n`,
|
|
254
|
+
);
|
|
255
|
+
for (const r of data) {
|
|
256
|
+
process.stdout.write(
|
|
257
|
+
` ${(r.share * 100).toFixed(1).padStart(5)} % ${r.keyword.padEnd(18)} ${r.rule.padEnd(32)} ` +
|
|
258
|
+
`pos ${String(r.hits)}/${String(r.foreign)} own-near ${String(r.own_near_miss_hits)}/${String(r.own_near_misses)} ` +
|
|
259
|
+
`foreign-near ${String(r.foreign_near_miss_hits)}\n`,
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function _isCliEntry(): boolean {
|
|
266
|
+
if (process.argv[1] === undefined) return false;
|
|
267
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
|
|
268
|
+
try {
|
|
269
|
+
return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
270
|
+
} catch {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (_isCliEntry()) {
|
|
276
|
+
process.exit(main());
|
|
277
|
+
}
|
|
@@ -53,8 +53,21 @@
|
|
|
53
53
|
* `command-only` and `flow-only` name a CANDIDATE for `user-invocable: false`,
|
|
54
54
|
* never a decision — see the sole-entry limit above.
|
|
55
55
|
*
|
|
56
|
+
* THE PER-PROFILE MENU, added by `road-to-a-menu-whose-precision-is-measured`
|
|
57
|
+
* 4.1. `--profile minimal|balanced|full|all` prints the menu byte count each
|
|
58
|
+
* shipped install profile delivers. Each profile's preset is read from its own
|
|
59
|
+
* file, and the answer is that all three are equal: no shipped preset declares
|
|
60
|
+
* a key that selects skills, so each one ships the whole menu.
|
|
61
|
+
*
|
|
62
|
+
* The equality note is WITHHELD when any profile carries a key listed in
|
|
63
|
+
* {@link SKILL_SELECTING_INI_KEYS}, and the key is named instead. That is the
|
|
64
|
+
* whole falsifiability claim, stated no wider than it holds: the byte count
|
|
65
|
+
* would not move — nothing here knows what such a key means — but the report
|
|
66
|
+
* stops asserting a conclusion whose premise has changed.
|
|
67
|
+
*
|
|
56
68
|
* Usage:
|
|
57
69
|
* ./scripts-run src/scripts/report_skill_menu_census # stdout summary
|
|
70
|
+
* ./scripts-run src/scripts/report_skill_menu_census --profile all
|
|
58
71
|
* ./scripts-run src/scripts/report_skill_menu_census --emit # write the artifact
|
|
59
72
|
* ./scripts-run src/scripts/report_skill_menu_census --emit --pin <sha>
|
|
60
73
|
*
|
|
@@ -313,8 +326,203 @@ function headSha(root: string): string {
|
|
|
313
326
|
return execFileSync('git', ['-C', root, 'rev-parse', 'HEAD'], { encoding: 'utf-8' }).trim();
|
|
314
327
|
}
|
|
315
328
|
|
|
329
|
+
// ── per-profile menu bytes (road-to-a-menu-whose-precision-is-measured 4.1) ──
|
|
330
|
+
|
|
331
|
+
/** The shipped install presets, mirroring `install.ts` SUPPORTED_PROFILES. */
|
|
332
|
+
export const PROFILES = ['minimal', 'balanced', 'full'] as const;
|
|
333
|
+
export type Profile = (typeof PROFILES)[number];
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Preset keys that would narrow the skill menu.
|
|
337
|
+
*
|
|
338
|
+
* EMPTY, and the emptiness is the finding rather than a stub. A preset selects
|
|
339
|
+
* `rule_loading_tier`, `discipline_profile` and `chat_history_frequency`; which
|
|
340
|
+
* SKILLS are written is decided by `packs:` frontmatter against the active pack
|
|
341
|
+
* set, which no preset names.
|
|
342
|
+
*
|
|
343
|
+
* It is a TRIPWIRE, not a selector, and the distinction is worth stating
|
|
344
|
+
* plainly because the first version of this comment overclaimed it. Nothing
|
|
345
|
+
* here knows what such a key would MEAN, so nothing here can apply one: the
|
|
346
|
+
* byte count would not move. What the list buys is that a preset carrying a
|
|
347
|
+
* listed key is NAMED in the output and the equality note is withheld — so the
|
|
348
|
+
* report stops asserting a conclusion whose premise has changed, instead of
|
|
349
|
+
* printing the same prose over a different tree.
|
|
350
|
+
*/
|
|
351
|
+
export const SKILL_SELECTING_INI_KEYS: readonly string[] = [];
|
|
352
|
+
|
|
353
|
+
/** Flat `key=value` read of a profile preset; `;` comments and blanks dropped. */
|
|
354
|
+
export function readProfileIni(root: string, profile: Profile): Record<string, string> {
|
|
355
|
+
const p = path.join(root, 'src', 'config', 'profiles', `${profile}.ini`);
|
|
356
|
+
const out: Record<string, string> = {};
|
|
357
|
+
for (const raw of fs.readFileSync(p, 'utf-8').split('\n')) {
|
|
358
|
+
const line = raw.trim();
|
|
359
|
+
if (line === '' || line.startsWith(';') || line.startsWith('#') || line.startsWith('[')) continue;
|
|
360
|
+
const eq = line.indexOf('=');
|
|
361
|
+
if (eq === -1) continue;
|
|
362
|
+
out[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();
|
|
363
|
+
}
|
|
364
|
+
return out;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export interface ProfileMenu {
|
|
368
|
+
readonly profile: Profile;
|
|
369
|
+
/** Skills this profile writes onto the model menu. */
|
|
370
|
+
readonly menuSkills: number;
|
|
371
|
+
/** Bytes of `- <name>: <description>\n`, the shape `censusSkillsCatalog` sums. */
|
|
372
|
+
readonly menuBytes: number;
|
|
373
|
+
/** chars/4, the estimator the payload budget uses. */
|
|
374
|
+
readonly tokensEstimate: number;
|
|
375
|
+
/** `declared_skill_catalogue_tokens` from the preset, or null when absent. */
|
|
376
|
+
readonly declaredCatalogueTokens: number | null;
|
|
377
|
+
/** Preset keys found that would narrow the menu. Empty today, by measurement. */
|
|
378
|
+
readonly selectingKeys: readonly string[];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* One profile's menu, computed from its preset plus the skill tree.
|
|
383
|
+
*
|
|
384
|
+
* The catalogue LINE is the same shape `preamble_byte_census.censusSkillsCatalog`
|
|
385
|
+
* sums — `- <name>: <description>\n`. The POPULATION deliberately is not, and the
|
|
386
|
+
* difference is stated rather than smoothed over: that census sums every
|
|
387
|
+
* `SKILL.md`, because the payload bucket it feeds is about what the host lists;
|
|
388
|
+
* this one drops a skill carrying `user-invocable: false` or
|
|
389
|
+
* `disable-model-invocation: true`, because a menu is what the MODEL may pick
|
|
390
|
+
* from. Two skills carry such a flag today, so over the same tree and the same
|
|
391
|
+
* line shape this report reads 311 B below the full-population sum. Expect the
|
|
392
|
+
* two to differ; a reader who finds them equal has found a defect in one.
|
|
393
|
+
*/
|
|
394
|
+
export function menuForProfile(root: string, profile: Profile): ProfileMenu {
|
|
395
|
+
const ini = readProfileIni(root, profile);
|
|
396
|
+
const selectingKeys = SKILL_SELECTING_INI_KEYS.filter((k) => k in ini);
|
|
397
|
+
const skillsDir = path.join(root, 'src', 'skills');
|
|
398
|
+
let menuSkills = 0;
|
|
399
|
+
let menuBytes = 0;
|
|
400
|
+
for (const entry of fs.readdirSync(skillsDir, { withFileTypes: true })) {
|
|
401
|
+
if (!entry.isDirectory()) continue;
|
|
402
|
+
const skillMd = path.join(skillsDir, entry.name, 'SKILL.md');
|
|
403
|
+
if (!fs.existsSync(skillMd)) continue;
|
|
404
|
+
const text = fs.readFileSync(skillMd, 'utf-8');
|
|
405
|
+
const flags = menuFlags(text);
|
|
406
|
+
if (flags.userInvocable === false || flags.disableModel === true) continue;
|
|
407
|
+
const name = /^name:\s*(\S.*?)\s*$/mu.exec(text.slice(0, 4000))?.[1] ?? entry.name;
|
|
408
|
+
const description = frontmatterDescription(text);
|
|
409
|
+
menuSkills += 1;
|
|
410
|
+
menuBytes += `- ${name}: ${description}\n`.length;
|
|
411
|
+
}
|
|
412
|
+
const declared = ini['declared_skill_catalogue_tokens'];
|
|
413
|
+
return {
|
|
414
|
+
profile,
|
|
415
|
+
menuSkills,
|
|
416
|
+
menuBytes,
|
|
417
|
+
tokensEstimate: Math.round(menuBytes / 4),
|
|
418
|
+
declaredCatalogueTokens: declared === undefined ? null : Number(declared),
|
|
419
|
+
selectingKeys,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* The `description:` value, folded lines included.
|
|
425
|
+
*
|
|
426
|
+
* A `[^\n]+` capture was measured 17.1 % low elsewhere in this tree because it
|
|
427
|
+
* truncates every folded multi-line description; this reads to the next
|
|
428
|
+
* top-level key instead.
|
|
429
|
+
*
|
|
430
|
+
* A double-quoted value has its escapes DECODED. Leaving them encoded counted
|
|
431
|
+
* `\"` as two characters and over-reported the menu by 56 B across 13 skills —
|
|
432
|
+
* small, but the same class of defect as the 17.1 % one above, and a function
|
|
433
|
+
* whose docstring cites that fix should not carry a second instance of it.
|
|
434
|
+
*/
|
|
435
|
+
export function frontmatterDescription(text: string): string {
|
|
436
|
+
if (!text.startsWith('---')) return '';
|
|
437
|
+
const end = text.indexOf('\n---', 3);
|
|
438
|
+
if (end === -1) return '';
|
|
439
|
+
const lines = text.slice(3, end).split('\n');
|
|
440
|
+
const at = lines.findIndex((l) => /^description:/u.test(l));
|
|
441
|
+
if (at === -1) return '';
|
|
442
|
+
const parts = [(lines[at] as string).replace(/^description:\s*/u, '')];
|
|
443
|
+
for (let i = at + 1; i < lines.length; i += 1) {
|
|
444
|
+
const l = lines[i] as string;
|
|
445
|
+
if (/^\S/u.test(l)) break;
|
|
446
|
+
parts.push(l.trim());
|
|
447
|
+
}
|
|
448
|
+
const joined = parts.join(' ').trim();
|
|
449
|
+
if (joined.length >= 2 && joined.startsWith('"') && joined.endsWith('"')) {
|
|
450
|
+
return joined.slice(1, -1).replace(/\\(["\\])/gu, '$1');
|
|
451
|
+
}
|
|
452
|
+
if (joined.length >= 2 && joined.startsWith("'") && joined.endsWith("'")) {
|
|
453
|
+
return joined.slice(1, -1).replace(/''/gu, "'");
|
|
454
|
+
}
|
|
455
|
+
return joined;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/** Render the per-profile menu table. Returns the lines, so tests read them. */
|
|
459
|
+
export function renderProfileMenus(menus: readonly ProfileMenu[]): string[] {
|
|
460
|
+
const L: string[] = [];
|
|
461
|
+
L.push('menu bytes per install profile (name + description, the catalogue shape):');
|
|
462
|
+
L.push(' profile skills menu_bytes ~tokens declared');
|
|
463
|
+
for (const m of menus) {
|
|
464
|
+
L.push(
|
|
465
|
+
` ${m.profile.padEnd(10)} ${String(m.menuSkills).padStart(6)} ` +
|
|
466
|
+
`${String(m.menuBytes).padStart(12)} ${String(m.tokensEstimate).padStart(9)} ` +
|
|
467
|
+
`${(m.declaredCatalogueTokens === null ? '—' : String(m.declaredCatalogueTokens)).padStart(10)}`,
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
const flagged = menus.filter((m) => m.selectingKeys.length > 0);
|
|
471
|
+
if (flagged.length > 0) {
|
|
472
|
+
L.push('');
|
|
473
|
+
L.push(' A preset declares a key that could select skills, so the equality below is NOT');
|
|
474
|
+
L.push(' asserted — the premise it rested on has changed. Keys found:');
|
|
475
|
+
for (const m of flagged) L.push(` ${m.profile}: ${m.selectingKeys.join(', ')}`);
|
|
476
|
+
return L;
|
|
477
|
+
}
|
|
478
|
+
const distinct = new Set(menus.map((m) => m.menuBytes));
|
|
479
|
+
if (menus.length > 1 && distinct.size === 1) {
|
|
480
|
+
L.push('');
|
|
481
|
+
L.push(
|
|
482
|
+
' All profiles report the SAME menu_bytes, and that is a measurement, not a',
|
|
483
|
+
);
|
|
484
|
+
L.push(
|
|
485
|
+
' placeholder: no preset declares a key that selects skills, so each ships the',
|
|
486
|
+
);
|
|
487
|
+
L.push(
|
|
488
|
+
' whole menu. The preset chooses which RULES activate; which SKILLS are written',
|
|
489
|
+
);
|
|
490
|
+
L.push(
|
|
491
|
+
' is decided by `packs:` frontmatter against the active pack set. A menu-bytes',
|
|
492
|
+
);
|
|
493
|
+
L.push(
|
|
494
|
+
' lever therefore has to move packs or the menu flags — changing profile does',
|
|
495
|
+
);
|
|
496
|
+
L.push(' nothing. The three presets already record this in their own comments.');
|
|
497
|
+
}
|
|
498
|
+
return L;
|
|
499
|
+
}
|
|
500
|
+
|
|
316
501
|
export function main(argv: readonly string[]): number {
|
|
317
502
|
const root = REPO_ROOT;
|
|
503
|
+
const profIdx = argv.indexOf('--profile');
|
|
504
|
+
if (profIdx !== -1) {
|
|
505
|
+
const want = argv[profIdx + 1] ?? 'all';
|
|
506
|
+
const chosen: Profile[] =
|
|
507
|
+
want === 'all' ? [...PROFILES] : PROFILES.includes(want as Profile) ? [want as Profile] : [];
|
|
508
|
+
if (chosen.length === 0) {
|
|
509
|
+
process.stderr.write(
|
|
510
|
+
`report_skill_menu_census: --profile expects ${PROFILES.join(' | ')} | all, got ${want}\n`,
|
|
511
|
+
);
|
|
512
|
+
return 2;
|
|
513
|
+
}
|
|
514
|
+
if (argv.includes('--emit')) {
|
|
515
|
+
// Refused rather than ignored: `--emit` writes the census artifact,
|
|
516
|
+
// `--profile` prints a table and writes nothing, and silently doing
|
|
517
|
+
// the second when the caller asked for both is how an artifact goes
|
|
518
|
+
// un-refreshed without anyone noticing.
|
|
519
|
+
process.stderr.write('report_skill_menu_census: --profile and --emit are separate runs\n');
|
|
520
|
+
return 2;
|
|
521
|
+
}
|
|
522
|
+
const menus = chosen.map((p) => menuForProfile(root, p));
|
|
523
|
+
process.stdout.write(`${renderProfileMenus(menus).join('\n')}\n`);
|
|
524
|
+
return 0;
|
|
525
|
+
}
|
|
318
526
|
const emit = argv.includes('--emit');
|
|
319
527
|
const pinIdx = argv.indexOf('--pin');
|
|
320
528
|
const pin = pinIdx !== -1 && pinIdx + 1 < argv.length ? (argv[pinIdx + 1] as string) : headSha(root);
|