@event4u/agent-config 16.2.0 → 16.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +89 -237
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +4 -4
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1167 -234
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +127 -75
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +5357 -6656
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2080 -1024
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +31965 -27154
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +6 -0
- package/dist/shared/skillRanking.js +74 -13
- package/docs/contracts/settings-classes.md +7 -5
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +62 -22
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +96 -3
- package/src/config/gate-violation-baselines.json +17 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/routing-coverage-seed.json +24 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +23 -71
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +116 -4
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_kernel_edit_ratified.ts +49 -11
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +150 -9
- package/src/scripts/hooks/block_config_weakening.ts +67 -2
- package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/rule_inject_hook.ts +757 -63
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
- package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +72 -185
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/self_review_gate.ts +62 -7
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -5
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +117 -11
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "The high-consequence rule class (road-to-rule-laws-that-can-stand Phase 2). The CRITERION lives in the `consequence_class` property of src/scripts/schemas/rule.schema.json and is the only thing that selects a member — this file is the list the criterion produced, not a list chosen first, which is why `excluded` carries a reason per row and is walked by id against the router. A rule earns a row by what its own law section obligates, never by its name or its pack. `members` is the whole class. `no_stub` is the subset whose law cannot stand in a stub today — missing, or over the 2,000-char ceiling — each with the reason; those project FULL-BODIED, which is strictly safer than a shortened copy, and the subset is what stops the class being quietly shrunk by not writing a law. A member in that state and NOT in `no_stub` fails the projection. Checked by tests/scripts/rule_consequence_class.test.ts.",
|
|
3
|
+
"criterion_ref": "src/scripts/schemas/rule.schema.json#/properties/consequence_class",
|
|
4
|
+
"members": {
|
|
5
|
+
"autonomous-execution": {
|
|
6
|
+
"clause": "authority-bypass",
|
|
7
|
+
"why": "The Hard Floor and the commit default are authority boundaries."
|
|
8
|
+
},
|
|
9
|
+
"broken-access-control": {
|
|
10
|
+
"clause": "security-boundary",
|
|
11
|
+
"why": "The law is the per-object ownership and tenant check before data is returned. Violating it hands one user another user's data."
|
|
12
|
+
},
|
|
13
|
+
"command-suggestion-policy": {
|
|
14
|
+
"clause": "authority-bypass",
|
|
15
|
+
"why": "The law is SUGGEST, NEVER INVOKE. Violating it starts a command flow the user never picked."
|
|
16
|
+
},
|
|
17
|
+
"decision-revisit-gate": {
|
|
18
|
+
"clause": "authority-bypass",
|
|
19
|
+
"why": "The law routes a reopened decision to the council by default and to the owner for the reserved set. Violating it executes an owner-reserved transition on the agent's own authority."
|
|
20
|
+
},
|
|
21
|
+
"doc-screenshot-hygiene": {
|
|
22
|
+
"clause": "irreversible-external",
|
|
23
|
+
"why": "The law calls a shipped screenshot with unredacted data an irreversible published egress, in those words."
|
|
24
|
+
},
|
|
25
|
+
"domain-safety-disclaimer": {
|
|
26
|
+
"clause": "authority-bypass",
|
|
27
|
+
"why": "The law refuses diagnosis and dosage outright and makes every advisory draft carry its disclaimer. Violating it issues a professional judgement the agent is not licensed to make."
|
|
28
|
+
},
|
|
29
|
+
"domain-safety-pii": {
|
|
30
|
+
"clause": "security-boundary",
|
|
31
|
+
"why": "The law keeps raw direct identifiers out of drafts, logs and exports. Violating it is the data exposure."
|
|
32
|
+
},
|
|
33
|
+
"domain-safety-retention": {
|
|
34
|
+
"clause": "irreversible-external",
|
|
35
|
+
"why": "The law forbids recommending deletion under audit, litigation or regulatory hold. Violating it destroys records that cannot be recovered."
|
|
36
|
+
},
|
|
37
|
+
"engineering-safety-floor": {
|
|
38
|
+
"clause": "irreversible-external",
|
|
39
|
+
"why": "The law restates the Hard Floor for deploys, production-trunk merges and production data. Every trigger it names is an action this agent cannot undo."
|
|
40
|
+
},
|
|
41
|
+
"evaluator-independence": {
|
|
42
|
+
"clause": "authority-bypass",
|
|
43
|
+
"why": "The law forbids authoring the verdict into an evaluator's prompt. Violating it manufactures the independent review a gate then relies on."
|
|
44
|
+
},
|
|
45
|
+
"fast-path-marker-visibility": {
|
|
46
|
+
"clause": "authority-bypass",
|
|
47
|
+
"why": "The marker is the only signal that a fast path resolved a decision instead of the user. Swallowing it hides the substitution."
|
|
48
|
+
},
|
|
49
|
+
"finance-safety-floor": {
|
|
50
|
+
"clause": "authority-bypass",
|
|
51
|
+
"why": "The law refuses a final invest or raise call. Violating it takes a decision the law assigns to the human."
|
|
52
|
+
},
|
|
53
|
+
"git-history-discipline": {
|
|
54
|
+
"clause": "irreversible-external",
|
|
55
|
+
"why": "The law forbids rewriting published history and dropping commits the session did not author. A force-push over someone else's work is not recoverable from here."
|
|
56
|
+
},
|
|
57
|
+
"image-likeness-and-rights": {
|
|
58
|
+
"clause": "irreversible-external",
|
|
59
|
+
"why": "The law gates a real person's likeness, a trademarked mark and a living artist's style behind explicit rights. The harm lands outside the repository and outlives the render."
|
|
60
|
+
},
|
|
61
|
+
"legal-safety-floor": {
|
|
62
|
+
"clause": "authority-bypass",
|
|
63
|
+
"why": "The law refuses a binding legal conclusion and stops outright at individual-case examination. Violating it performs regulated activity."
|
|
64
|
+
},
|
|
65
|
+
"lethal-trifecta-guard": {
|
|
66
|
+
"clause": "security-boundary",
|
|
67
|
+
"why": "The law forbids shipping private-data access, untrusted ingestion and external comms on one autonomous path. That combination is the exfiltration shape itself."
|
|
68
|
+
},
|
|
69
|
+
"low-impact-corpus-privacy-floor": {
|
|
70
|
+
"clause": "security-boundary",
|
|
71
|
+
"why": "The law is a non-bypassable redaction gate on entries that leave the project repo. It is the last check before an upstream push."
|
|
72
|
+
},
|
|
73
|
+
"question-not-instruction": {
|
|
74
|
+
"clause": "authority-bypass",
|
|
75
|
+
"why": "A question is not authorization to act — the purest authority-bypass clause in the tree."
|
|
76
|
+
},
|
|
77
|
+
"runtime-safety": {
|
|
78
|
+
"clause": "security-boundary",
|
|
79
|
+
"why": "The rule bounds what an `automated` skill may execute and which handlers are allowlisted."
|
|
80
|
+
},
|
|
81
|
+
"secret-vcs-guard": {
|
|
82
|
+
"clause": "security-boundary",
|
|
83
|
+
"why": "The law stops before a credential reaches version control. Once committed it is leaked in every clone, and only rotation undoes it."
|
|
84
|
+
},
|
|
85
|
+
"security-sensitive-stop": {
|
|
86
|
+
"clause": "security-boundary",
|
|
87
|
+
"why": "The law requires a threat pass before the first edit to auth, tenancy, billing, secrets, uploads and public endpoints. It is the gate the other security rules assume ran."
|
|
88
|
+
},
|
|
89
|
+
"session-canary": {
|
|
90
|
+
"clause": "authority-bypass",
|
|
91
|
+
"why": "The honesty clause forbids papering over a dropped canary. Faking continuity removes the user's only signal that the session is degrading, which is their decision to make."
|
|
92
|
+
},
|
|
93
|
+
"settings-ask-protocol": {
|
|
94
|
+
"clause": "authority-bypass",
|
|
95
|
+
"why": "The law calls a silent permissive default a decision taken in the user's name, and forbids it."
|
|
96
|
+
},
|
|
97
|
+
"source-confidentiality": {
|
|
98
|
+
"clause": "security-boundary",
|
|
99
|
+
"why": "The law keeps derivation attribution out of the tracked tree. A disclosure that lands in git history is not withdrawable."
|
|
100
|
+
},
|
|
101
|
+
"strategy-safety-floor": {
|
|
102
|
+
"clause": "authority-bypass",
|
|
103
|
+
"why": "The law refuses a final enter / build / buy / reorg call and names the human decision owner."
|
|
104
|
+
},
|
|
105
|
+
"tool-safety": {
|
|
106
|
+
"clause": "security-boundary",
|
|
107
|
+
"why": "The rule is the deny-by-default tool allowlist and the no-hidden-credentials floor."
|
|
108
|
+
},
|
|
109
|
+
"untrusted-input-defense": {
|
|
110
|
+
"clause": "security-boundary",
|
|
111
|
+
"why": "The law makes fetched, tool, file, RAG and MCP content data and never instructions. Violating it is how an attacker's text becomes the agent's plan."
|
|
112
|
+
},
|
|
113
|
+
"user-interrupt-priority": {
|
|
114
|
+
"clause": "authority-bypass",
|
|
115
|
+
"why": "The law stops the current task on a new instruction and asks before resuming. Silent resume continues work the user withdrew."
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"no_stub": {
|
|
119
|
+
"autonomous-execution": {
|
|
120
|
+
"clause": "authority-bypass",
|
|
121
|
+
"why": "The Hard Floor and the commit default are authority boundaries.",
|
|
122
|
+
"reason": "No heading matching `Iron Law`: the rule states its floors under `## Hard Floor` and its bound in a fence under `## Validation-loop budget`. Promoting one of those to a law heading is authoring a law, which is a change to what the rule obligates and is out of scope for a projection change. Projects full-bodied until a law section is written deliberately."
|
|
123
|
+
},
|
|
124
|
+
"legal-safety-floor": {
|
|
125
|
+
"clause": "authority-bypass",
|
|
126
|
+
"why": "The law refuses a binding legal conclusion and stops outright at individual-case examination.",
|
|
127
|
+
"reason": "Law section is 2,023 characters, 23 over the hard ceiling, and carries a dated exception in rule-law-ceilings.json. It cannot stand in a stub until the RDG STOP block is reviewed out of the law and into the body beside it."
|
|
128
|
+
},
|
|
129
|
+
"question-not-instruction": {
|
|
130
|
+
"clause": "authority-bypass",
|
|
131
|
+
"why": "A question is not authorization to act — the purest authority-bypass clause in the tree.",
|
|
132
|
+
"reason": "No heading matching `Iron Law`: the rule opens with a bare fence under its title. The fence is the law and promoting it needs a heading, which is a rule edit rather than a projection one."
|
|
133
|
+
},
|
|
134
|
+
"runtime-safety": {
|
|
135
|
+
"clause": "security-boundary",
|
|
136
|
+
"why": "The rule bounds what an `automated` skill may execute and which handlers are allowlisted.",
|
|
137
|
+
"reason": "No heading matching `Iron Law`: the constraints are a bullet list under `## Constraints`. Named by the roadmap's own Context as one of the two sharpest cases in the 35."
|
|
138
|
+
},
|
|
139
|
+
"tool-safety": {
|
|
140
|
+
"clause": "security-boundary",
|
|
141
|
+
"why": "The rule is the deny-by-default tool allowlist and the no-hidden-credentials floor.",
|
|
142
|
+
"reason": "No heading matching `Iron Law`: the floor is stated under `## Constraints` and `## Scoped grants`. Named by the roadmap's own Context as one of the two sharpest cases in the 35."
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"excluded": {
|
|
146
|
+
"active-remediation": "A spotted issue left unfixed costs quality and rework. Its one genuinely high-consequence branch — a live cross-user exposure — is already `broken-access-control`'s law, which is in the class.",
|
|
147
|
+
"delegation-policy": "Dispatch shape, not authority: it delegates nothing a Hard Floor would stop, and says so.",
|
|
148
|
+
"downstream-changes": "A missed caller is a broken build, which is loud and recoverable.",
|
|
149
|
+
"history-discipline": "Audit coverage is an auditability property. Its privacy interlock points at `domain-safety-pii`, which is in the class.",
|
|
150
|
+
"media-governance-routing": "A routing rule: it surfaces the project-local media policies. The rights obligation itself is `image-likeness-and-rights`, which is in the class.",
|
|
151
|
+
"media-sync-ground-truth": "The spend gate is real but the obligation its law states is a sourcing one — timing and singer come from the transcribed audio. The paid-render confirmation it builds on is `non-destructive-by-default`, a kernel rule that is never thinned.",
|
|
152
|
+
"no-attribution-footers": "An attribution footer is external but editable, so the action is not irreversible.",
|
|
153
|
+
"no-decorative-emojis-in-git-surfaces": "An emoji in a PR title or a commit subject is external but editable, and the fix is an edit rather than a rotation or a retraction. Same reason as no-attribution-footers, one surface over.",
|
|
154
|
+
"no-pr-progress-comments": "A noisy PR thread is a cost, not a boundary, and a comment can be deleted.",
|
|
155
|
+
"playbook-precedence": "Its propose-never-silently-run clause defers to the same floor `non-destructive-by-default` holds; on its own it decides which procedure to follow.",
|
|
156
|
+
"provider-lifecycle-discipline": "Tier declaration and a refuse-and-surface ask. The spend floor it defers to is a kernel rule.",
|
|
157
|
+
"scale-discipline": "An exhausted connection pool is an availability failure, not a security boundary.",
|
|
158
|
+
"senior-engineering-discipline": "The anchor that ROUTES to the invisible controls. The controls themselves are in the class; the anchor is not, or the criterion would admit every rule that mentions security.",
|
|
159
|
+
"think-before-action": "Analysis discipline. Violating it wastes work."
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Per-rule law-section and body ceilings (road-to-rule-laws-that-can-stand Phase 1). SHRINK-ONLY on every axis: an id may LEAVE `missing`, never join it; a recorded exception is a ceiling the rule may fall below and never rise above. Raising one to clear a red is the config-weakening move this repo blocks by construction — `--write-baseline` refuses to raise, it only re-records the smaller of old and current. A rule at its exception is not thereby correct, only not worse. Regenerate with `lint_rule_law_section --write-baseline`; never hand-edit the counts, but DO hand-edit `owner`, `review` and `reason` — those are the review contract and the generator only seeds them.",
|
|
3
|
+
"measured_at_commit": "30f7d21f6",
|
|
4
|
+
"missing": [
|
|
5
|
+
"architecture",
|
|
6
|
+
"artifact-drafting-protocol",
|
|
7
|
+
"artifact-engagement-recording",
|
|
8
|
+
"augment-edit-discipline",
|
|
9
|
+
"autonomous-execution",
|
|
10
|
+
"cli-output-handling",
|
|
11
|
+
"commit-conventions",
|
|
12
|
+
"context-hygiene",
|
|
13
|
+
"copilot-routing",
|
|
14
|
+
"devcontainer-routing",
|
|
15
|
+
"docker-commands",
|
|
16
|
+
"external-code-graph-interop",
|
|
17
|
+
"improve-before-implement",
|
|
18
|
+
"laravel-routing",
|
|
19
|
+
"laravel-translations",
|
|
20
|
+
"linked-projects-onboarding-gate",
|
|
21
|
+
"markdown-safe-codeblocks",
|
|
22
|
+
"minimal-safe-diff",
|
|
23
|
+
"missing-tool-handling",
|
|
24
|
+
"model-recommendation",
|
|
25
|
+
"onboarding-gate",
|
|
26
|
+
"php-coding",
|
|
27
|
+
"question-not-instruction",
|
|
28
|
+
"reviewer-awareness",
|
|
29
|
+
"role-mode-adherence",
|
|
30
|
+
"rule-type-governance",
|
|
31
|
+
"runtime-safety",
|
|
32
|
+
"skill-improvement-trigger",
|
|
33
|
+
"skill-quality",
|
|
34
|
+
"slash-command-routing-policy",
|
|
35
|
+
"source-of-truth",
|
|
36
|
+
"symfony-routing",
|
|
37
|
+
"test-first",
|
|
38
|
+
"tool-safety",
|
|
39
|
+
"upstream-proposal"
|
|
40
|
+
],
|
|
41
|
+
"law_exceptions": {
|
|
42
|
+
"legal-safety-floor": {
|
|
43
|
+
"chars": 2023,
|
|
44
|
+
"owner": "agent-config-maintainer",
|
|
45
|
+
"review": "2026-12-01",
|
|
46
|
+
"reason": "Three laws a regulator reads literally (no final legal call, consent gate, council gate) plus the RDG STOP block whose wording is quoted verbatim to the user. At 2023 characters it is 23 over the ceiling, so the review is about whether the STOP block belongs in the law or beside it."
|
|
47
|
+
},
|
|
48
|
+
"preservation-guard": {
|
|
49
|
+
"chars": 2418,
|
|
50
|
+
"owner": "agent-config-maintainer",
|
|
51
|
+
"review": "2026-12-01",
|
|
52
|
+
"reason": "The law IS a checklist: each bullet names a passage class that must survive a transform, and check_condensation reads the same list. Shortening the prose would shorten the contract the gate enforces. Review target: move the reject criteria out and leave the preservation checklist."
|
|
53
|
+
},
|
|
54
|
+
"roadmap-progress-sync": {
|
|
55
|
+
"chars": 5387,
|
|
56
|
+
"owner": "agent-config-maintainer",
|
|
57
|
+
"review": "2026-12-01",
|
|
58
|
+
"reason": "Three separate Iron Laws (dashboard sync, checkbox cadence, no silent archive) plus the preservation test that resolves a deferred item. Splitting them would create three rules with one trigger set; collapsing them would drop an obligation. Review target: move the resolution procedure under Iron Law 3 behind load_context and keep the three laws."
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"body_exceptions": {
|
|
62
|
+
"code-provenance": {
|
|
63
|
+
"chars": 8106,
|
|
64
|
+
"owner": "agent-config-maintainer",
|
|
65
|
+
"review": "2026-12-01",
|
|
66
|
+
"reason": "Two layers (code borrows and the knowledge/harvest layer) each with its own law, plus the no-CI-detector honesty section recording a measured gate decision."
|
|
67
|
+
},
|
|
68
|
+
"context-hygiene": {
|
|
69
|
+
"chars": 8320,
|
|
70
|
+
"owner": "agent-config-maintainer",
|
|
71
|
+
"review": "2026-12-01",
|
|
72
|
+
"reason": "Carries the freshness ladder, the 3-failure rule, loop detection and the 15/25 read-loop rule, each with its own self-check. Already migrated once into context-hygiene-mechanics and re-grew."
|
|
73
|
+
},
|
|
74
|
+
"decision-revisit-gate": {
|
|
75
|
+
"chars": 8566,
|
|
76
|
+
"owner": "agent-config-maintainer",
|
|
77
|
+
"review": "2026-12-01",
|
|
78
|
+
"reason": "The largest rule in the tree. Carries the five-step gate, the two descriptive axes, the owner-reserved table and an honest-enforcement section. Phase 1.4 of road-to-rule-laws-that-can-stand names it as a first mover for the load_context split."
|
|
79
|
+
},
|
|
80
|
+
"design-fidelity": {
|
|
81
|
+
"chars": 8777,
|
|
82
|
+
"owner": "agent-config-maintainer",
|
|
83
|
+
"review": "2026-12-01",
|
|
84
|
+
"reason": "Carries the artefact-maturity axis, the fidelity-mode table and the routing matrix. Phase 1.4 names it as a first mover."
|
|
85
|
+
},
|
|
86
|
+
"roadmap-progress-sync": {
|
|
87
|
+
"chars": 9308,
|
|
88
|
+
"owner": "agent-config-maintainer",
|
|
89
|
+
"review": "2026-12-01",
|
|
90
|
+
"reason": "Three laws plus the deferred-item resolution procedure and the later/PR-gate dispositions. The dispositions are mechanism, not obligation, and are the load_context candidate."
|
|
91
|
+
},
|
|
92
|
+
"settings-ask-protocol": {
|
|
93
|
+
"chars": 8099,
|
|
94
|
+
"owner": "agent-config-maintainer",
|
|
95
|
+
"review": "2026-12-01",
|
|
96
|
+
"reason": "Carries the four slots, the seven keys, the non-interactive rule and the consent-verdict contract. The key inventory is reference material and is the load_context candidate."
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -188,6 +188,21 @@ export interface ClaudePathsPlan {
|
|
|
188
188
|
dropped: { pattern: string; reason: 'unresolved-placeholder' | 'over-budget' | 'mixed-triggers' }[];
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* The two trigger keys `derive_trigger_globs` turns into a host glob. Kept
|
|
193
|
+
* beside it deliberately: the day a third path-shaped key is added there, this
|
|
194
|
+
* set is the other half of the same edit, and a reader looking at either one
|
|
195
|
+
* sees the pair.
|
|
196
|
+
*/
|
|
197
|
+
const PATH_SHAPED_TRIGGER_KEYS: ReadonlySet<string> = new Set(['file_pattern', 'path_prefix']);
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Keys on a trigger object that match nothing. `reason:` documents why the
|
|
201
|
+
* trigger exists; counting it would make every annotated path trigger look
|
|
202
|
+
* mixed and scope nothing at all.
|
|
203
|
+
*/
|
|
204
|
+
const NON_MATCHING_TRIGGER_KEYS: ReadonlySet<string> = new Set(['reason']);
|
|
205
|
+
|
|
191
206
|
/**
|
|
192
207
|
* Does this rule declare any trigger that is NOT path-shaped?
|
|
193
208
|
*
|
|
@@ -199,6 +214,18 @@ export interface ClaudePathsPlan {
|
|
|
199
214
|
* rule loads unconditionally. The emitter fed both semantics from one list, so
|
|
200
215
|
* a rule that declared keywords *and* one path glob silently became
|
|
201
216
|
* path-gated-only on Claude.
|
|
217
|
+
*
|
|
218
|
+
* **The test is a negation, not a list of non-path kinds**, and the difference
|
|
219
|
+
* is not stylistic. The predicate used to enumerate `keyword` and `phrase`,
|
|
220
|
+
* which left `command` — a prompt route like any other — uncounted:
|
|
221
|
+
* `roadmap-progress-sync` declares one `path_prefix` and three `command`
|
|
222
|
+
* triggers, so it was emitted with an exclusive `paths:` and its three command
|
|
223
|
+
* routes never fired on this host. A list can only ever be as current as its
|
|
224
|
+
* last edit; the schema's `additionalProperties: false` means a new match key
|
|
225
|
+
* arrives as a deliberate schema change, and until someone teaches
|
|
226
|
+
* `derive_trigger_globs` to make a glob from it, treating it as promptable is
|
|
227
|
+
* the fail-safe reading — the rule stays unconditional rather than silently
|
|
228
|
+
* narrowing to a path it does not have.
|
|
202
229
|
*/
|
|
203
230
|
export function _has_non_path_trigger(meta: Record<string, unknown>): boolean {
|
|
204
231
|
const triggers = meta['triggers'];
|
|
@@ -206,8 +233,21 @@ export function _has_non_path_trigger(meta: Record<string, unknown>): boolean {
|
|
|
206
233
|
for (const t of triggers) {
|
|
207
234
|
if (t === null || typeof t !== 'object' || Array.isArray(t)) continue;
|
|
208
235
|
const obj = t as Record<string, unknown>;
|
|
209
|
-
|
|
210
|
-
|
|
236
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
237
|
+
if (PATH_SHAPED_TRIGGER_KEYS.has(key) || NON_MATCHING_TRIGGER_KEYS.has(key)) continue;
|
|
238
|
+
// A string that is not blank, or ANY non-string value. The schema
|
|
239
|
+
// types all five match keys as strings today, so the second half is
|
|
240
|
+
// for the key that arrives later: a `keyword: ["a","b"]` read as
|
|
241
|
+
// "not a string, so not a trigger" would silently narrow the rule
|
|
242
|
+
// to a path it does not have, which is the exact failure the
|
|
243
|
+
// negation above exists to prevent. Undefined and null are the one
|
|
244
|
+
// shape that means "absent".
|
|
245
|
+
if (typeof value === 'string') {
|
|
246
|
+
if (value.trim() !== '') return true;
|
|
247
|
+
} else if (value !== undefined && value !== null) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
211
251
|
}
|
|
212
252
|
return false;
|
|
213
253
|
}
|
|
@@ -230,8 +270,10 @@ export function _claude_paths_plan(meta: Record<string, unknown>): ClaudePathsPl
|
|
|
230
270
|
const globs: string[] = [];
|
|
231
271
|
const dropped: ClaudePathsPlan['dropped'] = [];
|
|
232
272
|
|
|
233
|
-
// A rule that ALSO declares
|
|
234
|
-
//
|
|
273
|
+
// A rule that ALSO declares a non-path trigger — keyword, phrase, command,
|
|
274
|
+
// or a match key added to the schema later — gets no `paths:` at all, and
|
|
275
|
+
// therefore keeps loading unconditionally on Claude Code. The predicate is
|
|
276
|
+
// a negation of the two path-shaped keys, deliberately: see its docblock.
|
|
235
277
|
//
|
|
236
278
|
// Emitting `paths:` here would narrow the rule to a path match and discard
|
|
237
279
|
// every keyword the author wrote, because this host reads the list as the
|
|
@@ -132,7 +132,7 @@ export function rewriteAndReport(
|
|
|
132
132
|
quiet: boolean,
|
|
133
133
|
info: (m: string) => void,
|
|
134
134
|
warn: (m: string) => void,
|
|
135
|
-
wrappers?: { wrapped: readonly string[]; reserved: readonly string[] },
|
|
135
|
+
wrappers?: { wrapped: readonly string[]; reserved: readonly string[]; foreign?: readonly string[] },
|
|
136
136
|
preserved: ReadonlySet<string> = new Set(),
|
|
137
137
|
): ClaudeRuleRewriteResult {
|
|
138
138
|
const result = rewriteClaudeRules(rulesDir, preserved);
|
|
@@ -157,6 +157,15 @@ export function rewriteAndReport(
|
|
|
157
157
|
'commands remain available',
|
|
158
158
|
);
|
|
159
159
|
}
|
|
160
|
+
if (wrappers.foreign !== undefined && wrappers.foreign.length > 0) {
|
|
161
|
+
// Reported, never removed. The name shadows a host built-in, but
|
|
162
|
+
// this package did not write the file, so deleting it would be
|
|
163
|
+
// taking a neighbour's command away without saying so.
|
|
164
|
+
info(
|
|
165
|
+
` claude-code: kept ${wrappers.foreign.length} neighbour command file(s) whose ` +
|
|
166
|
+
`name is a Claude Code built-in (${wrappers.foreign.join(', ')}); not ours to remove`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
160
169
|
}
|
|
161
170
|
if (result.rewritten > 0 && !quiet) {
|
|
162
171
|
info(
|
|
@@ -44,6 +44,14 @@ import {
|
|
|
44
44
|
_emit_windsurf_rule,
|
|
45
45
|
strip_frontmatter,
|
|
46
46
|
} from '../scripts/condense.js';
|
|
47
|
+
import {
|
|
48
|
+
WINDSURFRULES_HEADER,
|
|
49
|
+
cleanOwnedOnly,
|
|
50
|
+
keptLine,
|
|
51
|
+
mayWriteRuleFile,
|
|
52
|
+
mayWriteWindsurfRules,
|
|
53
|
+
ownedPaths,
|
|
54
|
+
} from './host_rule_ownership.js';
|
|
47
55
|
|
|
48
56
|
function _ruleFiles(rulesDir: string): string[] {
|
|
49
57
|
return fs
|
|
@@ -60,63 +68,64 @@ function _ruleFiles(rulesDir: string): string[] {
|
|
|
60
68
|
});
|
|
61
69
|
}
|
|
62
70
|
|
|
63
|
-
/** Remove entries not in `valid` (mirror of condense's `_clean_modern_dir`). */
|
|
64
|
-
function _cleanDir(dir: string, valid: ReadonlySet<string>): void {
|
|
65
|
-
let entries: string[];
|
|
66
|
-
try {
|
|
67
|
-
entries = fs.readdirSync(dir);
|
|
68
|
-
} catch {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
for (const name of entries) {
|
|
72
|
-
if (name === 'README.md' || valid.has(name)) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
const full = path.join(dir, name);
|
|
76
|
-
try {
|
|
77
|
-
if (fs.lstatSync(full).isDirectory()) {
|
|
78
|
-
fs.rmSync(full, { recursive: true, force: true });
|
|
79
|
-
} else {
|
|
80
|
-
fs.unlinkSync(full);
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
/* best-effort clean */
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
71
|
export function emitCursor(rulesDir: string, projectRoot: string): number {
|
|
89
72
|
const targetDir = path.join(projectRoot, '.cursor', 'rules');
|
|
90
73
|
const files = _ruleFiles(rulesDir);
|
|
74
|
+
const owned = ownedPaths(projectRoot);
|
|
91
75
|
const valid = new Set<string>();
|
|
76
|
+
let blocked = 0;
|
|
92
77
|
for (const src of files) {
|
|
93
78
|
const name = `${path.basename(src, '.md')}.mdc`;
|
|
94
|
-
|
|
79
|
+
const target = path.join(targetDir, name);
|
|
80
|
+
// Ownership BEFORE the write: a neighbour's file under one of our
|
|
81
|
+
// names would otherwise be destroyed and then skipped by the cleanup
|
|
82
|
+
// pass, which only looks at names this run did not emit.
|
|
83
|
+
if (!mayWriteRuleFile(target, owned)) {
|
|
84
|
+
blocked += 1;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
_emit_cursor_mdc(src, target);
|
|
95
88
|
valid.add(name);
|
|
96
89
|
}
|
|
97
|
-
|
|
90
|
+
const { kept } = cleanOwnedOnly(targetDir, valid, owned);
|
|
91
|
+
const line = keptLine(kept + blocked);
|
|
92
|
+
if (line !== null) process.stdout.write(`cursor: ${line}\n`);
|
|
98
93
|
return files.length;
|
|
99
94
|
}
|
|
100
95
|
|
|
101
96
|
export function emitWindsurf(rulesDir: string, projectRoot: string): number {
|
|
102
97
|
const perRuleDir = path.join(projectRoot, '.windsurf', 'rules');
|
|
103
98
|
const files = _ruleFiles(rulesDir);
|
|
99
|
+
const owned = ownedPaths(projectRoot);
|
|
104
100
|
const valid = new Set<string>();
|
|
101
|
+
let blocked = 0;
|
|
105
102
|
for (const src of files) {
|
|
106
103
|
const name = path.basename(src);
|
|
107
|
-
|
|
104
|
+
const target = path.join(perRuleDir, name);
|
|
105
|
+
if (!mayWriteRuleFile(target, owned)) {
|
|
106
|
+
blocked += 1;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
_emit_windsurf_rule(src, target);
|
|
108
110
|
valid.add(name);
|
|
109
111
|
}
|
|
110
|
-
|
|
112
|
+
const { kept } = cleanOwnedOnly(perRuleDir, valid, owned);
|
|
113
|
+
const line = keptLine(kept + blocked);
|
|
114
|
+
if (line !== null) process.stdout.write(`windsurf: ${line}\n`);
|
|
111
115
|
|
|
112
116
|
// Concatenated legacy surface — same format as the projection-path
|
|
113
117
|
// generator (condense.generate_windsurfrules), consumer-sourced header.
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
+
const target = path.join(projectRoot, '.windsurfrules');
|
|
119
|
+
if (mayWriteWindsurfRules(target, owned)) {
|
|
120
|
+
const parts = [`${WINDSURFRULES_HEADER}\n`];
|
|
121
|
+
for (const src of files) {
|
|
122
|
+
const content = strip_frontmatter(fs.readFileSync(src, 'utf-8'));
|
|
123
|
+
parts.push(`---\n\n${content.trim()}\n`);
|
|
124
|
+
}
|
|
125
|
+
fs.writeFileSync(target, parts.join('\n') + '\n', 'utf-8');
|
|
126
|
+
} else {
|
|
127
|
+
process.stdout.write('windsurf: kept: 1 neighbour file(s) (.windsurfrules)\n');
|
|
118
128
|
}
|
|
119
|
-
fs.writeFileSync(path.join(projectRoot, '.windsurfrules'), parts.join('\n') + '\n', 'utf-8');
|
|
120
129
|
return files.length;
|
|
121
130
|
}
|
|
122
131
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rule scope governing a GLOBAL deploy.
|
|
3
|
+
*
|
|
4
|
+
* Moved out of `src/scripts/install.ts` by
|
|
5
|
+
* `road-to-an-installed-layer-that-is-thinned` step 1.1, which adds the thinning
|
|
6
|
+
* call to the same deploy loop. `check_source_size_budget` is a one-way ratchet
|
|
7
|
+
* with no per-change headroom, and this repository's stated convention is that
|
|
8
|
+
* the total falls through EXTRACTION and never rises through a baseline edit —
|
|
9
|
+
* the same reason `claudeRuleRewrite` holds the claude-code post-copy reporting
|
|
10
|
+
* rather than the installer. This function is the nearest self-contained block
|
|
11
|
+
* to the change: it is the predicate the deploy loop resolves once per run, it
|
|
12
|
+
* reaches nothing else in the installer, and its four environment touches are
|
|
13
|
+
* already parameters in all but name.
|
|
14
|
+
*
|
|
15
|
+
* BEHAVIOUR IS UNCHANGED, DELIBERATELY. The body is the installer's, verbatim
|
|
16
|
+
* apart from the four injected seams below; `install.ts` keeps a wrapper of the
|
|
17
|
+
* same name and signature, so its re-export and every caller and test see what
|
|
18
|
+
* they saw before. A behaviour change smuggled into an extraction is the one
|
|
19
|
+
* thing that would make the line saving not worth having.
|
|
20
|
+
*
|
|
21
|
+
* The seams are injected rather than imported because each one is an
|
|
22
|
+
* install-time decision the installer owns: where the global settings doc lives,
|
|
23
|
+
* how this build reads and parses YAML, what the packaged template says, and
|
|
24
|
+
* where a warning goes.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { LEGACY_ALL, ruleScopeFromSettings, type RuleScope } from './rule_scope.js';
|
|
28
|
+
|
|
29
|
+
export interface GlobalRuleScopeInputs {
|
|
30
|
+
/** The global settings file, or `null` when no artefact exists at all. */
|
|
31
|
+
readonly settingsPath: string | null;
|
|
32
|
+
/** The package being installed from. */
|
|
33
|
+
readonly packageRoot: string;
|
|
34
|
+
/** Read a file as text; throws like `fs.readFileSync` when it cannot. */
|
|
35
|
+
readonly readText: (p: string) => string;
|
|
36
|
+
/** Parse YAML permissively — anything unparseable comes back non-object. */
|
|
37
|
+
readonly parseYaml: (text: string) => unknown;
|
|
38
|
+
/** The packaged template settings, read only on a genuinely fresh machine. */
|
|
39
|
+
readonly loadDefaults: () => Record<string, unknown>;
|
|
40
|
+
/** Where a loud fallback goes. */
|
|
41
|
+
readonly warn: (message: string) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isPlainObject(v: unknown): boolean {
|
|
45
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the rule scope governing THIS global deploy — the same way the wizard
|
|
50
|
+
* does (`src/server/routes/install.ts::_resolveRuleScope`), so the two global
|
|
51
|
+
* paths cannot ship different rule sets for the same settings.
|
|
52
|
+
*
|
|
53
|
+
* Settings resolution mirrors `_resolve_scoped_projection` above: an existing
|
|
54
|
+
* global settings doc is authoritative, and only a genuinely fresh machine falls
|
|
55
|
+
* through to the packaged template. Any read or parse failure resolves to
|
|
56
|
+
* `LEGACY_ALL` — over-shipping is the safe direction, and the compat exclusion
|
|
57
|
+
* (`source-of-truth.md`) still applies even then.
|
|
58
|
+
*/
|
|
59
|
+
export function resolveGlobalRuleScope(inputs: GlobalRuleScopeInputs): RuleScope {
|
|
60
|
+
const { packageRoot, warn } = inputs;
|
|
61
|
+
const settings_path = inputs.settingsPath;
|
|
62
|
+
|
|
63
|
+
// No global settings artefact at all — a genuinely fresh machine. Fall
|
|
64
|
+
// through to the packaged template silently: there is no user decision to
|
|
65
|
+
// contradict, and this is the documented upgrade-compat path.
|
|
66
|
+
if (settings_path === null) {
|
|
67
|
+
try {
|
|
68
|
+
return ruleScopeFromSettings(inputs.loadDefaults(), packageRoot);
|
|
69
|
+
} catch {
|
|
70
|
+
return LEGACY_ALL;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// A doc EXISTS, so the user has expressed a configuration. Failing to read
|
|
75
|
+
// it is not the same as not having one: falling back to legacy-all here
|
|
76
|
+
// ships the maintainer-only rules the user may have deliberately scoped out,
|
|
77
|
+
// and `_load_yaml_doc` would report that as an indistinguishable `{}`. So
|
|
78
|
+
// parse it explicitly and be LOUD when it does not parse — over-shipping
|
|
79
|
+
// stays the safe direction, but it must not be a silent one.
|
|
80
|
+
let text: string;
|
|
81
|
+
try {
|
|
82
|
+
text = inputs.readText(settings_path);
|
|
83
|
+
} catch (e) {
|
|
84
|
+
warn(
|
|
85
|
+
`could not read ${settings_path} (${String(e)}) — rule scoping falls back ` +
|
|
86
|
+
'to legacy-all, so ALL rules including maintainer-only ones will be ' +
|
|
87
|
+
'installed. Fix the file to restore scoping.',
|
|
88
|
+
);
|
|
89
|
+
return LEGACY_ALL;
|
|
90
|
+
}
|
|
91
|
+
const parsed = inputs.parseYaml(text);
|
|
92
|
+
if (!isPlainObject(parsed)) {
|
|
93
|
+
warn(
|
|
94
|
+
`${settings_path} is not a YAML mapping — rule scoping falls back to ` +
|
|
95
|
+
'legacy-all, so ALL rules including maintainer-only ones will be ' +
|
|
96
|
+
'installed. Fix the file to restore scoping.',
|
|
97
|
+
);
|
|
98
|
+
return LEGACY_ALL;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
return ruleScopeFromSettings(parsed as Record<string, unknown>, packageRoot);
|
|
102
|
+
} catch (e) {
|
|
103
|
+
warn(
|
|
104
|
+
`could not derive rule scope from ${settings_path} (${String(e)}) — ` +
|
|
105
|
+
'falling back to legacy-all; ALL rules will be installed.',
|
|
106
|
+
);
|
|
107
|
+
return LEGACY_ALL;
|
|
108
|
+
}
|
|
109
|
+
}
|