@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
|
@@ -266,6 +266,17 @@ export const MERGEABLE_KEYS = [
|
|
|
266
266
|
// GUI; whitelisting decides only whether the value SURVIVES the merge
|
|
267
267
|
// (ADR-271, road-to-design-intent-conformance 2.3).
|
|
268
268
|
'design.fidelity_mode',
|
|
269
|
+
// `lean_projection.*` is a per-MACHINE setting and the install it governs is
|
|
270
|
+
// a user-scope one: the layer being thinned is `~/.claude/rules`, which
|
|
271
|
+
// belongs to the machine and not to any checkout. Without these two rows a
|
|
272
|
+
// consumer who wrote the opt-in into the user-global file got no error, no
|
|
273
|
+
// warning and no effect — the same silent-filter defect the two entries
|
|
274
|
+
// above repair, reaching a third key, and unsatisfiable-by-construction on
|
|
275
|
+
// an ADR-020 global-only install, where no project layer exists to carry it.
|
|
276
|
+
// Whitelisting decides only whether a value SURVIVES the merge: it sets
|
|
277
|
+
// nothing, and `installerThinsHost` still refuses a template-only value.
|
|
278
|
+
'lean_projection.mode',
|
|
279
|
+
'lean_projection.hosts',
|
|
269
280
|
];
|
|
270
281
|
/** The shipped template, relative to the package root. */
|
|
271
282
|
const TEMPLATE_RELATIVE = path.join('src', 'config', 'agent-settings.template.yml');
|
|
@@ -70,17 +70,19 @@ export function build_claude_hook_matrix(manifest_path) {
|
|
|
70
70
|
const claude_events = (platforms['claude'] ?? {}) || {};
|
|
71
71
|
const aliasesAll = (manifest['native_event_aliases'] ?? {});
|
|
72
72
|
const aliases = (aliasesAll['claude'] ?? {}) || {};
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
// Iterating the ALIAS map, not the event map, because the relation is
|
|
74
|
+
// many-natives-to-one-event and the inversion this replaced silently lost
|
|
75
|
+
// every native but the last. `PostToolUse` and `PostToolUseFailure` both
|
|
76
|
+
// lower to `post_tool_use`; building `ac_to_native` would have kept one of
|
|
77
|
+
// them and UNBOUND the other, turning a routing fix into a routing
|
|
78
|
+
// regression that no existing test could see. Pinned by
|
|
79
|
+
// `before_complete_failure_envelope.test.ts` ("both natives stay bound").
|
|
77
80
|
const matrix = {};
|
|
78
|
-
for (const [
|
|
81
|
+
for (const [native, ac_raw] of Object.entries(aliases)) {
|
|
82
|
+
const ac_event = String(ac_raw);
|
|
83
|
+
const concerns = claude_events[ac_event];
|
|
79
84
|
if (!concerns || (Array.isArray(concerns) && concerns.length === 0))
|
|
80
85
|
continue;
|
|
81
|
-
const native = ac_to_native[ac_event];
|
|
82
|
-
if (native === undefined)
|
|
83
|
-
continue;
|
|
84
86
|
// Bundle fast path (road-to-hook-latency-repair Phase 2): invoke the
|
|
85
87
|
// precompiled dispatcher bundle directly — no bash shim, no CLI boot
|
|
86
88
|
// (measured ~450-500 ms CLI vs ~110 ms bundle per event on a 1-vCPU
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a host actually loads, measured in the host's own unit (step 0.1 of
|
|
3
|
+
* `road-to-a-rule-carrier-that-works-outside-the-repo`).
|
|
4
|
+
*
|
|
5
|
+
* THE QUESTION NOTHING IN THIS TREE COULD ANSWER. Every existing figure for the
|
|
6
|
+
* installed layer counts raw bytes of whole files: `censusRuleDir` sums
|
|
7
|
+
* `statSync().size`, `charsAtRoot` does the same for a directory, and
|
|
8
|
+
* `check_preamble_payload_budget` reads both. A host does not load frontmatter
|
|
9
|
+
* as instruction — it is the routing surface, which the router has already
|
|
10
|
+
* read — and it does not render HTML comments, which are authoring scaffolding.
|
|
11
|
+
* So the number a reader wants when they ask "how much instruction is this
|
|
12
|
+
* consumer under" has never been computed here.
|
|
13
|
+
*
|
|
14
|
+
* THE NUMBER IS THEREFORE NOT COMPARABLE WITH ANY PUBLISHED BASELINE, and that
|
|
15
|
+
* is stated here rather than discovered by someone holding the two side by
|
|
16
|
+
* side. `chars` below is strictly smaller than the byte figures in
|
|
17
|
+
* `budgets.yml`, `rule-activation-census.json` or the payload ratchet, and the
|
|
18
|
+
* gap is not a constant — it is whatever that particular corpus spends on
|
|
19
|
+
* frontmatter and comments.
|
|
20
|
+
*
|
|
21
|
+
* ONE LIBRARY, FOUR CONSUMERS. The report CLI is the only one wired in this
|
|
22
|
+
* change (Phase 0 makes no behavior change), and the shape is the reason the
|
|
23
|
+
* other three named in step 0.1 — CI, `doctor`, the upgrade receipt — can use
|
|
24
|
+
* it without a second reader: every input is a PARAMETER. `home`, `projectRoot`
|
|
25
|
+
* and `manifestPath` are supplied by the caller, never read off the process, so
|
|
26
|
+
* a test, a temporary `HOME` and a real machine are the same call with
|
|
27
|
+
* different arguments. That is also what makes the step's "install into a
|
|
28
|
+
* temporary HOME" reachable at all, and it is the fact that refutes
|
|
29
|
+
* `check_standing_rule_delivery`'s header: a user-scope install IS observable
|
|
30
|
+
* from CI, because the installer takes `HOME` from the environment.
|
|
31
|
+
*
|
|
32
|
+
* WHAT `package_owned` AND `foreign` MEAN, because the honest answer is three
|
|
33
|
+
* valued and the report has two columns. `recordedOwnership` distinguishes
|
|
34
|
+
* `recorded-unchanged`, `recorded-modified` and `unknown`, where `unknown` is
|
|
35
|
+
* explicitly "this tree cannot say" rather than "foreign". The report folds the
|
|
36
|
+
* first two into `package_owned` — both are files the manifest claims — and
|
|
37
|
+
* reports the third as `foreign`, which therefore reads "not claimed by this
|
|
38
|
+
* install", never "written by someone else". A machine with no manifest reports
|
|
39
|
+
* every file foreign, which is the correct reading of no evidence and is why
|
|
40
|
+
* {@link InstalledLayerReport.manifest_present} is in the output.
|
|
41
|
+
*/
|
|
42
|
+
import * as fs from 'node:fs';
|
|
43
|
+
import * as path from 'node:path';
|
|
44
|
+
import { fileURLToPath } from 'node:url';
|
|
45
|
+
import { GLOBAL_RULE_DIRS, PROJECT_RULE_DIRS, globalRuleLayerPath, } from '../../install/globalRuleLayers.js';
|
|
46
|
+
import { NO_RECORDED_HASHES, readRecordedHashes } from '../../install/recordedOwnership.js';
|
|
47
|
+
import { ruleBody } from './rule_law_section.js';
|
|
48
|
+
/** How many files the per-directory ranking carries. Step 0.1 fixes it at 20. */
|
|
49
|
+
export const TOP_FILES = 20;
|
|
50
|
+
/**
|
|
51
|
+
* The fraction of a published limit at which the report warns.
|
|
52
|
+
*
|
|
53
|
+
* 0.8 is step 1.4's number, not a tuned one. It is a WARNING threshold and
|
|
54
|
+
* never a gate: crossing it changes what the report says and nothing else, so
|
|
55
|
+
* no install fails here.
|
|
56
|
+
*/
|
|
57
|
+
export const LIMIT_WARN_FRACTION = 0.8;
|
|
58
|
+
/**
|
|
59
|
+
* Whether the host loads this file on every session rather than on a path match.
|
|
60
|
+
*
|
|
61
|
+
* `paths:` at the start of a line is the whole test, and it is the host's own
|
|
62
|
+
* convention rather than this package's: `claudeRuleRewrite.ts` states it from
|
|
63
|
+
* the emitting side — "with it a rule loads on a path match, without it the
|
|
64
|
+
* rule loads unconditionally". `rule_activation_census.projection_reading` asks
|
|
65
|
+
* the installed tree the same question with the same regex, so a file counted
|
|
66
|
+
* unconditional here is counted unconditional there.
|
|
67
|
+
*
|
|
68
|
+
* SOURCE-SIDE CLASSIFICATION IS A DIFFERENT QUESTION and deliberately not used.
|
|
69
|
+
* `classify_rule` reads `alwaysApply` and `type: always` to tell `always` from
|
|
70
|
+
* `unconditional`, which matters when you are deciding what to emit. This
|
|
71
|
+
* reads what WAS emitted, where the distinction has already been spent: an
|
|
72
|
+
* Iron-Law rule and an untriggered tier-2 rule both arrive without `paths:` and
|
|
73
|
+
* both load every session, which is the only property the host acts on.
|
|
74
|
+
*/
|
|
75
|
+
export function isUnconditional(text) {
|
|
76
|
+
return !/^paths:/m.test(text);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Measure one directory.
|
|
80
|
+
*
|
|
81
|
+
* `.md` only, matching `censusRuleDir` and `topRulesByCost`, so the FILE count
|
|
82
|
+
* is comparable with the existing byte censuses even though the character count
|
|
83
|
+
* is not. Cursor's `.mdc` tree is therefore read as zero files, which is the
|
|
84
|
+
* same blind spot every other census in this tree has and is not fixed here —
|
|
85
|
+
* fixing it in one reader and not the others would make two counts that
|
|
86
|
+
* disagree, which is worse than one that is openly partial.
|
|
87
|
+
*/
|
|
88
|
+
export function readLayer(host, scope, dir, recorded) {
|
|
89
|
+
const empty = {
|
|
90
|
+
files: 0,
|
|
91
|
+
unconditional: 0,
|
|
92
|
+
chars: 0,
|
|
93
|
+
package_owned: 0,
|
|
94
|
+
foreign: 0,
|
|
95
|
+
package_owned_chars: 0,
|
|
96
|
+
foreign_chars: 0,
|
|
97
|
+
top: [],
|
|
98
|
+
};
|
|
99
|
+
let names;
|
|
100
|
+
try {
|
|
101
|
+
names = fs.readdirSync(dir);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return { host, scope, dir, present: false, ...empty };
|
|
105
|
+
}
|
|
106
|
+
const readings = [];
|
|
107
|
+
for (const name of names.sort()) {
|
|
108
|
+
if (!name.endsWith('.md'))
|
|
109
|
+
continue;
|
|
110
|
+
const abs = path.join(dir, name);
|
|
111
|
+
let text;
|
|
112
|
+
try {
|
|
113
|
+
const st = fs.statSync(abs);
|
|
114
|
+
if (!st.isFile())
|
|
115
|
+
continue;
|
|
116
|
+
text = fs.readFileSync(abs, 'utf-8');
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
continue; // a file that cannot be read is not a file the host loads
|
|
120
|
+
}
|
|
121
|
+
// RECORDED-BUT-MODIFIED IS STILL RECORDED. The report's two columns
|
|
122
|
+
// answer "does this install claim the file"; `classifyOwnership` answers
|
|
123
|
+
// the finer question the upgrade path needs — whether the bytes still
|
|
124
|
+
// match — and folding that in here would give a column three meanings.
|
|
125
|
+
const owned = recorded.has(abs);
|
|
126
|
+
readings.push({
|
|
127
|
+
file: name,
|
|
128
|
+
// THE STRIP IS THE PROJECTOR'S OWN. `ruleBody` is what
|
|
129
|
+
// `project_thin_rules` and the delivery carrier both call, so "what
|
|
130
|
+
// a host loads" and "what a delivery carries" cannot drift into two
|
|
131
|
+
// spellings of the same measurement.
|
|
132
|
+
chars: ruleBody(text).length,
|
|
133
|
+
unconditional: isUnconditional(text),
|
|
134
|
+
package_owned: owned,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
const top = [...readings]
|
|
138
|
+
// RANKED BY THE SAME MEASURE AS THE TOTAL, which is why
|
|
139
|
+
// `preamble_byte_census.topRulesByCost` is not reused here: it ranks by
|
|
140
|
+
// `statSync().size`, so its list and this total would be in different
|
|
141
|
+
// units and the largest file by one could be absent from the other.
|
|
142
|
+
.sort((a, b) => b.chars - a.chars || a.file.localeCompare(b.file))
|
|
143
|
+
.slice(0, TOP_FILES);
|
|
144
|
+
return {
|
|
145
|
+
host,
|
|
146
|
+
scope,
|
|
147
|
+
dir,
|
|
148
|
+
present: true,
|
|
149
|
+
files: readings.length,
|
|
150
|
+
unconditional: readings.filter((r) => r.unconditional).length,
|
|
151
|
+
chars: readings.reduce((n, r) => n + r.chars, 0),
|
|
152
|
+
package_owned: readings.filter((r) => r.package_owned).length,
|
|
153
|
+
foreign: readings.filter((r) => !r.package_owned).length,
|
|
154
|
+
package_owned_chars: readings.reduce((n, r) => n + (r.package_owned ? r.chars : 0), 0),
|
|
155
|
+
foreign_chars: readings.reduce((n, r) => n + (r.package_owned ? 0 : r.chars), 0),
|
|
156
|
+
top,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Where the limits live, derived from this module rather than from `cwd`.
|
|
161
|
+
*
|
|
162
|
+
* The two `..` hops climb from `src/scripts/_lib` to `src/`, which is where
|
|
163
|
+
* `config/` lives — NOT to the package root, though the comment said so until
|
|
164
|
+
* 2026-10-05. The result is correct and the arithmetic stated for it was not,
|
|
165
|
+
* which is the half a future reader would trust when changing the hops.
|
|
166
|
+
*
|
|
167
|
+
* `fileURLToPath`, NOT `new URL(...).pathname` — the claimed parity with
|
|
168
|
+
* `default_template_path()` was only half true until 2026-10-05. A `pathname`
|
|
169
|
+
* percent-encodes, so a package under a directory with a space resolved to
|
|
170
|
+
* `/Users/x/My%20Projects/...`, and on Windows it yields a leading-slash drive
|
|
171
|
+
* path. Either way the read fails, `loadHostInstructionLimits` swallows it and
|
|
172
|
+
* returns an empty map, and EVERY host then reads `unpublished` with `warn`
|
|
173
|
+
* false — the budget measurement degrading to "not measured" with no signal,
|
|
174
|
+
* which is the one failure mode this file's own limit table was written to
|
|
175
|
+
* avoid.
|
|
176
|
+
*/
|
|
177
|
+
export function defaultHostLimitsPath() {
|
|
178
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'config', 'host-instruction-limits.json');
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Read the published-limit table.
|
|
182
|
+
*
|
|
183
|
+
* TOLERANT IN ONE DIRECTION ONLY. An unreadable or malformed file yields an
|
|
184
|
+
* EMPTY table, so every host reads `unpublished` and nothing warns — a reading
|
|
185
|
+
* this tree cannot stand behind must never become a warning it can. A present
|
|
186
|
+
* entry whose `limit` is not a positive finite number is treated the same way,
|
|
187
|
+
* because a `0` or a string would otherwise make every install look saturated.
|
|
188
|
+
*/
|
|
189
|
+
export function loadHostInstructionLimits(file = defaultHostLimitsPath()) {
|
|
190
|
+
const out = new Map();
|
|
191
|
+
let raw;
|
|
192
|
+
try {
|
|
193
|
+
raw = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return out; // no table ⇒ no limits ⇒ no warnings
|
|
197
|
+
}
|
|
198
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
199
|
+
return out;
|
|
200
|
+
for (const [host, v] of Object.entries(raw)) {
|
|
201
|
+
if (host.startsWith('_'))
|
|
202
|
+
continue; // `_comment` and friends are not hosts
|
|
203
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
204
|
+
continue;
|
|
205
|
+
const e = v;
|
|
206
|
+
const n = e.limit;
|
|
207
|
+
const limit = typeof n === 'number' && Number.isFinite(n) && n > 0 ? n : null;
|
|
208
|
+
const k = e.kind;
|
|
209
|
+
const kind = limit === null
|
|
210
|
+
? 'unpublished'
|
|
211
|
+
: k === 'vendor-published' || k === 'reported'
|
|
212
|
+
? k
|
|
213
|
+
: 'reported'; // a cited figure with no stated kind is the weaker one
|
|
214
|
+
out.set(host, { limit, kind });
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Fold the per-directory readings into one row per host, against its limit.
|
|
220
|
+
*
|
|
221
|
+
* Exported so a caller holding layers it built itself — the install receipt,
|
|
222
|
+
* which measures before and after — can produce the same rows without
|
|
223
|
+
* re-reading the tree.
|
|
224
|
+
*/
|
|
225
|
+
export function buildHostLimitRows(layers, limits) {
|
|
226
|
+
const byHost = new Map();
|
|
227
|
+
for (const l of layers) {
|
|
228
|
+
if (!l.present)
|
|
229
|
+
continue;
|
|
230
|
+
const acc = byHost.get(l.host) ?? { chars: 0, owned: 0, foreign: 0 };
|
|
231
|
+
acc.chars += l.chars;
|
|
232
|
+
acc.owned += l.package_owned_chars;
|
|
233
|
+
acc.foreign += l.foreign_chars;
|
|
234
|
+
byHost.set(l.host, acc);
|
|
235
|
+
}
|
|
236
|
+
// EVERY host that has a directory gets a row, present or not — a host whose
|
|
237
|
+
// layer is absent reads 0 against its limit, which is a real answer and the
|
|
238
|
+
// one step 3.5 asks for ("one row per host with a published limit").
|
|
239
|
+
for (const l of layers)
|
|
240
|
+
if (!byHost.has(l.host))
|
|
241
|
+
byHost.set(l.host, { chars: 0, owned: 0, foreign: 0 });
|
|
242
|
+
// AND every host the LIMITS table knows, whether or not a layer reached it.
|
|
243
|
+
// Rows were layer-driven while the requirement is limit-driven, so a limit
|
|
244
|
+
// recorded for a host the layer map does not list disappeared silently —
|
|
245
|
+
// the two sources agree today, which means they can only diverge in the
|
|
246
|
+
// direction the code did not cover.
|
|
247
|
+
for (const [host, e] of limits)
|
|
248
|
+
if (e.limit !== null && !byHost.has(host)) {
|
|
249
|
+
byHost.set(host, { chars: 0, owned: 0, foreign: 0 });
|
|
250
|
+
}
|
|
251
|
+
const rows = [];
|
|
252
|
+
for (const host of [...byHost.keys()].sort()) {
|
|
253
|
+
const a = byHost.get(host);
|
|
254
|
+
const e = limits.get(host) ?? { limit: null, kind: 'unpublished' };
|
|
255
|
+
const fraction = e.limit === null ? null : a.chars / e.limit;
|
|
256
|
+
rows.push({
|
|
257
|
+
host,
|
|
258
|
+
limit: e.limit,
|
|
259
|
+
kind: e.kind,
|
|
260
|
+
chars: a.chars,
|
|
261
|
+
package_owned_chars: a.owned,
|
|
262
|
+
foreign_chars: a.foreign,
|
|
263
|
+
fraction,
|
|
264
|
+
warn: fraction !== null && fraction >= LIMIT_WARN_FRACTION,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
return rows;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Read every host rule directory in both scopes.
|
|
271
|
+
*
|
|
272
|
+
* BOTH SCOPES, BECAUSE THE HOST UNIONS THEM. A reading of the global layer
|
|
273
|
+
* alone would understate a consumer whose project carries its own rules, and
|
|
274
|
+
* the carrier's own scope filter reads the union for the same reason
|
|
275
|
+
* (`rule_layer_overlap.hostRuleLayerIds`).
|
|
276
|
+
*/
|
|
277
|
+
export function buildInstalledLayerReport(opts) {
|
|
278
|
+
const manifestPath = opts.manifestPath ?? null;
|
|
279
|
+
const recorded = manifestPath === null
|
|
280
|
+
? NO_RECORDED_HASHES
|
|
281
|
+
: readRecordedHashes(manifestPath, opts.projectRoot);
|
|
282
|
+
const layers = [];
|
|
283
|
+
for (const host of Object.keys(GLOBAL_RULE_DIRS).sort()) {
|
|
284
|
+
const dir = globalRuleLayerPath(host, opts.home);
|
|
285
|
+
if (dir === null)
|
|
286
|
+
continue;
|
|
287
|
+
layers.push(readLayer(host, 'global', dir, recorded));
|
|
288
|
+
}
|
|
289
|
+
for (const rel of Object.keys(PROJECT_RULE_DIRS).sort()) {
|
|
290
|
+
const host = PROJECT_RULE_DIRS[rel];
|
|
291
|
+
layers.push(readLayer(host, 'project', path.join(opts.projectRoot, rel), recorded));
|
|
292
|
+
}
|
|
293
|
+
const totals = layers.reduce((acc, l) => ({
|
|
294
|
+
files: acc.files + l.files,
|
|
295
|
+
unconditional: acc.unconditional + l.unconditional,
|
|
296
|
+
chars: acc.chars + l.chars,
|
|
297
|
+
package_owned: acc.package_owned + l.package_owned,
|
|
298
|
+
foreign: acc.foreign + l.foreign,
|
|
299
|
+
package_owned_chars: acc.package_owned_chars + l.package_owned_chars,
|
|
300
|
+
foreign_chars: acc.foreign_chars + l.foreign_chars,
|
|
301
|
+
}), {
|
|
302
|
+
files: 0,
|
|
303
|
+
unconditional: 0,
|
|
304
|
+
chars: 0,
|
|
305
|
+
package_owned: 0,
|
|
306
|
+
foreign: 0,
|
|
307
|
+
package_owned_chars: 0,
|
|
308
|
+
foreign_chars: 0,
|
|
309
|
+
});
|
|
310
|
+
const limits = buildHostLimitRows(layers, loadHostInstructionLimits(opts.hostLimitsPath ?? defaultHostLimitsPath()));
|
|
311
|
+
return {
|
|
312
|
+
home: opts.home,
|
|
313
|
+
project_root: opts.projectRoot,
|
|
314
|
+
host_version: opts.hostVersion ?? 'unknown',
|
|
315
|
+
manifest_present: manifestPath !== null && fs.existsSync(manifestPath),
|
|
316
|
+
layers,
|
|
317
|
+
limits,
|
|
318
|
+
totals,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/** The report as lines, for a terminal. One directory per block. */
|
|
322
|
+
export function renderInstalledLayerReport(report) {
|
|
323
|
+
const out = [];
|
|
324
|
+
out.push(`installed layer — host ${report.host_version}, HOME ${report.home}`);
|
|
325
|
+
out.push(`project ${report.project_root}`);
|
|
326
|
+
out.push(report.manifest_present
|
|
327
|
+
? 'ownership: read from the installed-tools manifest'
|
|
328
|
+
: 'ownership: NO manifest resolved — every file reads foreign, which is no evidence rather than a finding');
|
|
329
|
+
for (const l of report.layers) {
|
|
330
|
+
if (!l.present) {
|
|
331
|
+
out.push(` ${l.host} (${l.scope}) — absent: ${l.dir}`);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
out.push(` ${l.host} (${l.scope}) — ${String(l.files)} files, ` +
|
|
335
|
+
`${String(l.unconditional)} unconditional, ${String(l.chars)} chars, ` +
|
|
336
|
+
`${String(l.package_owned)} package-owned / ${String(l.foreign)} foreign`);
|
|
337
|
+
for (const f of l.top) {
|
|
338
|
+
out.push(` ${String(f.chars).padStart(7)} ${f.unconditional ? 'uncond' : 'scoped'} ${f.file}`);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const t = report.totals;
|
|
342
|
+
out.push(` TOTAL — ${String(t.files)} files, ${String(t.unconditional)} unconditional, ` +
|
|
343
|
+
`${String(t.chars)} chars, ${String(t.package_owned)} package-owned / ${String(t.foreign)} foreign`);
|
|
344
|
+
out.push(...renderHostLimitRows(report.limits));
|
|
345
|
+
return out;
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* The budget block — one row per host, against its published limit.
|
|
349
|
+
*
|
|
350
|
+
* Extracted so the REPORT and the INSTALL RECEIPT print the same bytes. They
|
|
351
|
+
* answer the same question at two moments, and a consumer comparing a receipt
|
|
352
|
+
* against a later report must not have to decide whether a wording difference
|
|
353
|
+
* means a measurement difference.
|
|
354
|
+
*/
|
|
355
|
+
export function renderHostLimitRows(rows) {
|
|
356
|
+
// ONE ROW PER HOST, against its published limit — steps 1.4 and 3.5. The
|
|
357
|
+
// combined figure is what the row is about: a consumer's own instruction
|
|
358
|
+
// files sit in the same budget as this package's, so a package-owned number
|
|
359
|
+
// alone would understate what the host is actually holding.
|
|
360
|
+
const out = [
|
|
361
|
+
'host instruction budgets — package-owned + foreign against the published limit',
|
|
362
|
+
];
|
|
363
|
+
for (const r of rows) {
|
|
364
|
+
const split = `${String(r.package_owned_chars)} package-owned + ` +
|
|
365
|
+
`${String(r.foreign_chars)} foreign = ${String(r.chars)} chars`;
|
|
366
|
+
if (r.limit === null) {
|
|
367
|
+
out.push(` ${r.host} — ${split}; no published limit recorded — not measured`);
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const pct = (r.fraction * 100).toFixed(1);
|
|
371
|
+
out.push(` ${r.host} — ${split}; ${pct}% of ${String(r.limit)} (${r.kind})` +
|
|
372
|
+
(r.warn
|
|
373
|
+
? ` — WARNING: at or past ${String(Math.round(LIMIT_WARN_FRACTION * 100))}% of the published limit`
|
|
374
|
+
: ''));
|
|
375
|
+
}
|
|
376
|
+
return out;
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=installed_layer.js.map
|
|
@@ -1,20 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `lean_projection.mode` — ONE definition of what the three modes mean
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
2
|
+
* `lean_projection.mode` — ONE definition of what the three modes mean, and
|
|
3
|
+
* since step 1.2 of `road-to-a-rule-carrier-that-works-outside-the-repo`, ONE
|
|
4
|
+
* reader that produces it.
|
|
5
|
+
*
|
|
6
|
+
* ── What this module used to be, and why that was not enough ──
|
|
7
|
+
*
|
|
8
|
+
* It owned the NORMALISATION and left each caller its own READER: the projector
|
|
9
|
+
* (`condense.ts`) resolved the value with a real YAML parse over the full
|
|
10
|
+
* settings cascade; the delivery concern (`hooks/rule_inject_hook.ts`) resolved
|
|
11
|
+
* it with an indentation-shaped read of `<cwd>/.agent-settings.yml` alone. The
|
|
12
|
+
* header argued that two readers were unavoidable and that two *normalisations*
|
|
13
|
+
* were the only thing worth preventing.
|
|
14
|
+
*
|
|
15
|
+
* Measured on 2026-10-02, that split was not a stylistic difference — it was a
|
|
16
|
+
* disagreement about WHICH FILE. The installer writes settings to
|
|
17
|
+
* `<root>/agents/settings/.agent-settings.yml` (`agent_settings.ts`'s canonical
|
|
18
|
+
* write target; `install.ts:4108`). The concern read `<root>/.agent-settings.yml`,
|
|
19
|
+
* the LEGACY location, and nothing else. On a normal install the concern
|
|
20
|
+
* therefore read a file that does not exist, got `''`, normalised it to
|
|
21
|
+
* `eager-all`, and closed its own gate — while the projector, reading the
|
|
22
|
+
* canonical file, had written thin stubs. That is the pointer arm the delivery
|
|
23
|
+
* mode exists to replace, reached by configuration rather than by choice, and
|
|
24
|
+
* it is a SECOND independent cause of the silence step 1.1 repaired: a consumer
|
|
25
|
+
* that fixed the package root alone would still have received nothing.
|
|
26
|
+
*
|
|
27
|
+
* The user-global layer was invisible to the concern for the same reason, which
|
|
28
|
+
* matters more than it sounds: ADR-020 installs are global-only, so for those
|
|
29
|
+
* consumers the ONLY layer carrying a mode is one the concern never opened.
|
|
30
|
+
*
|
|
31
|
+
* ── D3: one resolver, not a parity test between three ──
|
|
32
|
+
*
|
|
33
|
+
* The roadmap's D3 records the choice and the reason — a parity test keeps
|
|
34
|
+
* three readers that can drift again, and this module already existed to be the
|
|
35
|
+
* one. `resolveLeanProjection` below is that resolver. It reads the layers in
|
|
36
|
+
* the order `load_agent_settings` defines (template base, user-global,
|
|
37
|
+
* project), through `project_settings_path`, which prefers the canonical file
|
|
38
|
+
* and falls back to the legacy one, so a hand-edited root file still works.
|
|
39
|
+
*
|
|
40
|
+
* ── Why the template path is passed in rather than resolved ──
|
|
41
|
+
*
|
|
42
|
+
* `agent_settings.default_template_path()` derives the package root from
|
|
43
|
+
* `import.meta.url` three directories up. That is correct for a module at
|
|
44
|
+
* `<pkg>/src/scripts/_lib/`; inside the composed hook bundle `import.meta.url`
|
|
45
|
+
* is `<pkg>/dist/hooks/dispatch.js`, so the same arithmetic yields the PARENT
|
|
46
|
+
* of the package and the template read misses. Verified in the built bundle,
|
|
47
|
+
* not inferred. With no template the base layer is `{}` and an unconfigured
|
|
48
|
+
* consumer resolves to `eager-all` — the silence again, one layer lower. So a
|
|
49
|
+
* caller that knows the real package root (the carrier does: the dispatcher
|
|
50
|
+
* passes it) hands it over, and the resolver reads the template from there.
|
|
51
|
+
*
|
|
52
|
+
* ── What has NOT changed ──
|
|
53
|
+
*
|
|
54
|
+
* Anything unrecognised — absent key, typo, `null`, a non-string — is still
|
|
55
|
+
* `eager-all`: the parser fallback, which is NOT the value the template ships
|
|
56
|
+
* (see the type below), because a mode nobody can spell must never silently
|
|
57
|
+
* thin the standing corpus. That fallback now fires only when no layer carried
|
|
58
|
+
* a value at all, rather than whenever the concern looked in the wrong place.
|
|
17
59
|
*/
|
|
60
|
+
import * as path from 'node:path';
|
|
61
|
+
import { load_agent_settings } from './agent_settings.js';
|
|
18
62
|
export const DEFAULT_LEAN_PROJECTION_MODE = 'eager-all';
|
|
19
63
|
/** Map a raw settings value onto a mode. Unrecognised → `eager-all`. */
|
|
20
64
|
export function normalizeLeanProjectionMode(raw) {
|
|
@@ -146,4 +190,163 @@ export function describeDroppedHosts(res) {
|
|
|
146
190
|
export function thinsHost(mode, hosts, hostId) {
|
|
147
191
|
return writesThinFiles(mode) && hosts.includes(hostId);
|
|
148
192
|
}
|
|
193
|
+
/**
|
|
194
|
+
* THE resolver. Every surface that asks "which delivery mode" calls this.
|
|
195
|
+
*
|
|
196
|
+
* Tolerant like everything else on a hook path: `load_agent_settings` answers
|
|
197
|
+
* with defaults on an unreadable or malformed file and never throws, and the
|
|
198
|
+
* normalisers above turn anything unrecognised into the safe value. A caller
|
|
199
|
+
* on a hot path pays ONE cascade read per prompt; `modeExplicit` is a lazy
|
|
200
|
+
* getter, so the second, template-isolated read happens only for a caller that
|
|
201
|
+
* actually reads provenance — which today is the installer and nothing else.
|
|
202
|
+
*/
|
|
203
|
+
export function resolveLeanProjection(opts = {}) {
|
|
204
|
+
// The LEGACY root path, deliberately, and not `project_settings_path`'s
|
|
205
|
+
// either-or pick. `load_agent_settings` expands whatever it is given into
|
|
206
|
+
// `[the file, <its dir>/agents/settings/.agent-settings.yml, <its dir>/
|
|
207
|
+
// agents/settings/.agent-settings.local.yml]` and merges them deepest-wins,
|
|
208
|
+
// so handing it the root path reads BOTH the legacy and the canonical file
|
|
209
|
+
// — which is strictly more than picking one, and is what a tree carrying
|
|
210
|
+
// both should resolve to. It also keeps one export out of this module's
|
|
211
|
+
// import list, which is runtime bytes in the composed hook bundle.
|
|
212
|
+
const file = opts.settingsPath ?? path.join(opts.projectRoot ?? process.cwd(), '.agent-settings.yml');
|
|
213
|
+
const tpl = opts.packageRoot == null
|
|
214
|
+
? null
|
|
215
|
+
: path.join(opts.packageRoot, 'src', 'config', 'agent-settings.template.yml');
|
|
216
|
+
let lean;
|
|
217
|
+
try {
|
|
218
|
+
lean = load_agent_settings(tpl === null ? { project_path: file } : { project_path: file, template_path: tpl })['lean_projection'];
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
/* a settings layer nothing can read must never fail a turn */
|
|
222
|
+
}
|
|
223
|
+
const obj = typeof lean === 'object' && lean !== null && !Array.isArray(lean) ? lean : {};
|
|
224
|
+
const o = obj;
|
|
225
|
+
return {
|
|
226
|
+
mode: normalizeLeanProjectionMode(o['mode'] ?? ''),
|
|
227
|
+
hosts: resolveLeanProjectionHosts(o['hosts']),
|
|
228
|
+
// LAZY, and the hot path is the reason. Provenance needs a SECOND,
|
|
229
|
+
// template-isolated cascade, and only the installer reads it — the
|
|
230
|
+
// delivery concern on `user_prompt_submit` destructures `{ mode, hosts }`
|
|
231
|
+
// and discards this field, so computing it eagerly doubled the per-prompt
|
|
232
|
+
// settings read for an answer nobody asked for. A getter keeps the
|
|
233
|
+
// field's shape (`readonly modeExplicit: boolean`) and charges only the
|
|
234
|
+
// caller that touches it.
|
|
235
|
+
get modeExplicit() {
|
|
236
|
+
return rawExplicitLeanProjectionMode(opts) !== '';
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* A path no tree contains, so `template_defaults` contributes nothing.
|
|
242
|
+
*
|
|
243
|
+
* This is the mechanism `load_agent_settings` documents for the purpose —
|
|
244
|
+
* "a test or tool that pins every other input can pin the defaults base too,
|
|
245
|
+
* and point it at a nonexistent file to isolate the cascade" — used here for a
|
|
246
|
+
* tool rather than a test. It is a reserved device filename on every platform
|
|
247
|
+
* this package runs on and is never created, so the read fails and the loader's
|
|
248
|
+
* own tolerance turns it into `{}`.
|
|
249
|
+
*
|
|
250
|
+
* The alternative — re-reading the YAML layers by hand — was rejected because
|
|
251
|
+
* it would be a SECOND reader of the same key, which is the precise defect step
|
|
252
|
+
* 1.2 of the carrier roadmap existed to remove. Isolating the base keeps one
|
|
253
|
+
* reader and changes only which layers it is given.
|
|
254
|
+
*/
|
|
255
|
+
const NO_TEMPLATE_LAYER = path.join(path.sep, 'dev', 'null', 'agent-config-absent-template.yml');
|
|
256
|
+
/**
|
|
257
|
+
* The RAW `lean_projection.mode` string from the user-controlled layers only,
|
|
258
|
+
* or `''` when no such layer carries it.
|
|
259
|
+
*
|
|
260
|
+
* Raw and un-normalised on purpose: {@link normalizeLeanProjectionMode} maps
|
|
261
|
+
* everything unrecognised — `''` included — onto `eager-all`, so a normalised
|
|
262
|
+
* answer cannot tell "the user chose eager-all" from "the user chose nothing".
|
|
263
|
+
* Provenance needs exactly that distinction, so it has to be read before the
|
|
264
|
+
* normaliser runs.
|
|
265
|
+
*/
|
|
266
|
+
export function rawExplicitLeanProjectionMode(opts = {}) {
|
|
267
|
+
const file = opts.settingsPath ?? path.join(opts.projectRoot ?? process.cwd(), '.agent-settings.yml');
|
|
268
|
+
let lean;
|
|
269
|
+
try {
|
|
270
|
+
lean = load_agent_settings({ project_path: file, template_path: NO_TEMPLATE_LAYER })['lean_projection'];
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
return ''; // a layer nothing can read states no preference
|
|
274
|
+
}
|
|
275
|
+
if (typeof lean !== 'object' || lean === null || Array.isArray(lean))
|
|
276
|
+
return '';
|
|
277
|
+
const m = lean['mode'];
|
|
278
|
+
return typeof m === 'string' ? m.trim() : '';
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Did a human ask for this mode, and is it the one the caller is gated on?
|
|
282
|
+
*
|
|
283
|
+
* The question an installer actually has. `modeExplicit` alone is not enough —
|
|
284
|
+
* a consumer who explicitly set `eager-all` has set the key explicitly and must
|
|
285
|
+
* NOT be thinned — so the two conditions are folded here rather than left to
|
|
286
|
+
* every caller to remember to combine.
|
|
287
|
+
*/
|
|
288
|
+
export function leanProjectionModeChosen(mode, opts = {}) {
|
|
289
|
+
const raw = rawExplicitLeanProjectionMode(opts);
|
|
290
|
+
return raw !== '' && normalizeLeanProjectionMode(raw) === mode;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* May the INSTALLER thin this host's rule tree?
|
|
294
|
+
*
|
|
295
|
+
* The host-aware sibling of {@link leanProjectionModeChosen}, and the predicate
|
|
296
|
+
* `road-to-an-installed-layer-that-is-thinned` step 1.1 keys on. It folds the
|
|
297
|
+
* three conditions that must hold together, once, so no caller has to remember
|
|
298
|
+
* to combine them:
|
|
299
|
+
*
|
|
300
|
+
* 1. **A human asked.** `modeExplicit` — false whenever the only layer carrying
|
|
301
|
+
* the key is the shipped template, which already says `delivery`. Reading the
|
|
302
|
+
* template as consent would thin every consumer's `~/.claude/rules` as a side
|
|
303
|
+
* effect of wiring a reader, which is the owner-reserved default flip (that
|
|
304
|
+
* roadmap's blocker, decision D4).
|
|
305
|
+
* 2. **The chosen mode actually writes stubs.** A consumer who explicitly chose
|
|
306
|
+
* `eager-all` has set the key and must NOT be thinned on the strength of
|
|
307
|
+
* having an opinion.
|
|
308
|
+
* 3. **This host is in scope.** The same `hosts:` list the projector honours, so
|
|
309
|
+
* installer and projector cannot disagree about which trees are thinned.
|
|
310
|
+
*
|
|
311
|
+
* ONE `resolveLeanProjection` call, which is why this is not two
|
|
312
|
+
* {@link leanProjectionModeChosen} calls: that one answers "is the chosen mode
|
|
313
|
+
* exactly X" and knows nothing about `hosts`, so a caller combining it with a
|
|
314
|
+
* host check by hand would re-create the fold this function exists to own.
|
|
315
|
+
*
|
|
316
|
+
* That is one CALL and two cascade READS here, because reading `modeExplicit`
|
|
317
|
+
* triggers its lazy getter and a second, template-isolated load. The installer
|
|
318
|
+
* runs once per deploy and does not care; the cost is named rather than rounded
|
|
319
|
+
* down because the same resolver serves the per-prompt delivery concern, which
|
|
320
|
+
* does NOT read provenance and therefore does not pay it.
|
|
321
|
+
*/
|
|
322
|
+
export function installerThinsHost(hostId, opts = {}) {
|
|
323
|
+
const { mode, hosts, modeExplicit } = resolveLeanProjection({
|
|
324
|
+
...opts,
|
|
325
|
+
settingsPath: opts.settingsPath ?? NO_PROJECT_LAYER,
|
|
326
|
+
});
|
|
327
|
+
return modeExplicit && thinsHost(mode, hosts.hosts, hostId);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* A path no tree contains, so the PROJECT cascade contributes nothing.
|
|
331
|
+
*
|
|
332
|
+
* The same device {@link NO_TEMPLATE_LAYER} uses, pointed at the other end of
|
|
333
|
+
* the cascade, and the reason is scope rather than isolation: the thing
|
|
334
|
+
* {@link installerThinsHost} gates is a mutation of `~/.claude/rules`, which
|
|
335
|
+
* belongs to the MACHINE. A per-checkout value must not decide it, in either
|
|
336
|
+
* direction — a project saying `delivery` would thin the layer every other
|
|
337
|
+
* project on that machine reads, and a project saying `eager-all` would
|
|
338
|
+
* suppress an opt-in the user wrote user-globally, because the project cascade
|
|
339
|
+
* merges last and wins.
|
|
340
|
+
*
|
|
341
|
+
* `load_agent_settings` reads `user_global_settings_paths()` regardless of what
|
|
342
|
+
* `project_path` it is given, so pointing the project layer at nothing leaves
|
|
343
|
+
* exactly the machine-global layers — which is the scope the installer's
|
|
344
|
+
* sibling `_resolve_global_rule_scope` already resolves for the same deploy.
|
|
345
|
+
* A caller may still pass an explicit `settingsPath` (tests pin one). A
|
|
346
|
+
* `projectRoot` handed to {@link installerThinsHost} is DISCARDED — the `??`
|
|
347
|
+
* chain terminates at `settingsPath` before `projectRoot` is consulted — which
|
|
348
|
+
* is the intended behaviour and is stated here because a caller passing it and
|
|
349
|
+
* expecting it honoured would otherwise get no signal.
|
|
350
|
+
*/
|
|
351
|
+
const NO_PROJECT_LAYER = path.join(path.sep, 'dev', 'null', 'agent-config-absent-project-settings.yml');
|
|
149
352
|
//# sourceMappingURL=lean_projection_mode.js.map
|