@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
|
@@ -45,14 +45,56 @@ import * as fs from 'node:fs';
|
|
|
45
45
|
import * as path from 'node:path';
|
|
46
46
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
47
47
|
|
|
48
|
+
// `yaml`, not `js-yaml`, and the choice is about the BUNDLE rather than about
|
|
49
|
+
// this file. Every concern is inlined into one `dist/hooks/dispatch.js` that
|
|
50
|
+
// every dispatch loads, and this import was the only `js-yaml` one left on that
|
|
51
|
+
// path while six other modules — `dispatch_hook.ts` and `host_lowering.ts`
|
|
52
|
+
// among them — already pulled `yaml`. Measured on 2026-10-01 from the esbuild
|
|
53
|
+
// metafile: `js-yaml` contributed 95,846 bytes (6.13 %) of a 1,564,211-byte
|
|
54
|
+
// bundle, paid on every hook event, for one call site. The behavioural delta is
|
|
55
|
+
// normalised in `parseSettingsDoc` below — three constraints, each MEASURED
|
|
56
|
+
// against the old reader rather than read off documentation — and pinned both by
|
|
57
|
+
// the characterization tests written before the swap and by a differential test
|
|
58
|
+
// that runs BOTH readers over one corpus and asserts the same refusal set.
|
|
59
|
+
import { parseDocument as parseYamlDocument } from 'yaml';
|
|
60
|
+
|
|
61
|
+
import {
|
|
62
|
+
buildSettingsClassIndex,
|
|
63
|
+
classOfPath,
|
|
64
|
+
parseSettingsClassRows,
|
|
65
|
+
type SettingsClass,
|
|
66
|
+
} from '../../shared/settingsClasses.js';
|
|
48
67
|
import { EDIT_TOOLS } from '../minimal_safe_diff_hook.js';
|
|
49
68
|
import { readHookStdin } from './hook_stdin.js';
|
|
69
|
+
import { EXIT_ALLOW, EXIT_BLOCK, EXIT_WARN } from './exit_codes.js';
|
|
50
70
|
|
|
51
71
|
const _HERE = fileURLToPath(import.meta.url);
|
|
52
72
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
/**
|
|
74
|
+
* This package's own root — where the shipped class contract lives.
|
|
75
|
+
*
|
|
76
|
+
* RESOLVED BY SEARCH, not by counting `..` segments. This file runs from three
|
|
77
|
+
* layouts: the source tree, an installed `node_modules/@event4u/agent-config/`,
|
|
78
|
+
* and inlined into `dist/hooks/dispatch.js`, where every module shares the
|
|
79
|
+
* BUNDLE's `import.meta.url` and a fixed hop count lands somewhere else
|
|
80
|
+
* entirely. A review flagged the fixed-hop version as resolving a different
|
|
81
|
+
* root from the one the package occupies; walking up to the nearest directory
|
|
82
|
+
* that actually carries the contract answers the question the guard is asking
|
|
83
|
+
* ("where is the contract") instead of a proxy for it.
|
|
84
|
+
*
|
|
85
|
+
* `null` when no ancestor carries it — which is the fail-closed input to
|
|
86
|
+
* `readClassIndex`, not a silent default root.
|
|
87
|
+
*/
|
|
88
|
+
export function findPackageRoot(from: string): string | null {
|
|
89
|
+
let dir = path.dirname(from);
|
|
90
|
+
for (let i = 0; i < 12; i++) {
|
|
91
|
+
if (fs.existsSync(path.join(dir, SETTINGS_CLASSES_RELATIVE))) return dir;
|
|
92
|
+
const up = path.dirname(dir);
|
|
93
|
+
if (up === dir) break;
|
|
94
|
+
dir = up;
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
56
98
|
|
|
57
99
|
/**
|
|
58
100
|
* The stated cap from `autonomous-execution` § Antipattern. Crossing it in one
|
|
@@ -81,7 +123,18 @@ const _PATH_KEYS: readonly string[] = ['file_path', 'path', 'target_file', 'file
|
|
|
81
123
|
* where "weakening" needs context a tool call does not carry (a baseline count
|
|
82
124
|
* may legitimately reset after a refactor); those warn and never block.
|
|
83
125
|
*/
|
|
84
|
-
export type ConfigKind = 'allowlist' | 'advisory' | null;
|
|
126
|
+
export type ConfigKind = 'allowlist' | 'advisory' | 'class-c' | null;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Project settings files whose keys this guard fences. User-global files are
|
|
130
|
+
* never in reach — the hook only sees a path a tool call named, and the writes
|
|
131
|
+
* that reach `~/.event4u/` go through `settings:set`, which applies its own
|
|
132
|
+
* per-key refusal.
|
|
133
|
+
*/
|
|
134
|
+
const CLASS_C_BASENAMES: readonly string[] = ['.agent-settings.yml', '.agent-settings.yaml', 'settings.json'];
|
|
135
|
+
|
|
136
|
+
/** Where the class contract lives, relative to the package root. */
|
|
137
|
+
export const SETTINGS_CLASSES_RELATIVE = 'docs/contracts/settings-classes.md';
|
|
85
138
|
|
|
86
139
|
/** Classify a target path into a config surface, or null for everything else. */
|
|
87
140
|
export function classify_target(p: string): ConfigKind {
|
|
@@ -96,9 +149,154 @@ export function classify_target(p: string): ConfigKind {
|
|
|
96
149
|
if (/-budget(s)?\.(json|ya?ml)$/.test(base) || base === 'budgets.yml') {
|
|
97
150
|
return 'advisory';
|
|
98
151
|
}
|
|
152
|
+
// `settings.json` only under a host directory: the bare name is common
|
|
153
|
+
// enough elsewhere that classifying it on the basename alone would fence
|
|
154
|
+
// files that carry no settings key at all.
|
|
155
|
+
if (base === 'settings.json') {
|
|
156
|
+
return /(^|\/)\.(claude|cursor|augment|windsurf)\/settings\.json$/.test(posix) ? 'class-c' : null;
|
|
157
|
+
}
|
|
158
|
+
if (CLASS_C_BASENAMES.includes(base)) {
|
|
159
|
+
return 'class-c';
|
|
160
|
+
}
|
|
99
161
|
return null;
|
|
100
162
|
}
|
|
101
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Leaf key paths of a parsed settings document, dotted.
|
|
166
|
+
*
|
|
167
|
+
* LEAVES ONLY, and the choice is load-bearing in both directions. A class-C key
|
|
168
|
+
* whose value is a MAP (`hooks`, say) has children that never appear as their
|
|
169
|
+
* own rows in the contract, so emitting only leaves and letting `classOfPath`
|
|
170
|
+
* walk up to the nearest classified ancestor is what makes `hooks.enabled`
|
|
171
|
+
* resolve to C. Emitting the interior nodes as well would double-count the same
|
|
172
|
+
* change and report a parent that nothing edited.
|
|
173
|
+
*/
|
|
174
|
+
export function leafPaths(value: unknown, prefix = ''): Map<string, string> {
|
|
175
|
+
const out = new Map<string, string>();
|
|
176
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
177
|
+
if (prefix !== '') out.set(prefix, JSON.stringify(value ?? null));
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
|
|
181
|
+
const key = prefix === '' ? k : `${prefix}.${k}`;
|
|
182
|
+
for (const [ck, cv] of leafPaths(v, key)) out.set(ck, cv);
|
|
183
|
+
}
|
|
184
|
+
return out;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Parse a settings document, or `null` when it is not parseable.
|
|
189
|
+
*
|
|
190
|
+
* `null` is NOT "no keys changed" — the caller treats it as an unreadable
|
|
191
|
+
* corpus and refuses, because a guard that allows whatever it cannot parse is
|
|
192
|
+
* bypassed by making the file unparseable for one call.
|
|
193
|
+
*
|
|
194
|
+
* THE YAML READER IS CONSTRAINED, and all three constraints exist to keep the
|
|
195
|
+
* refusal set the same as `js-yaml`'s rather than to express a preference.
|
|
196
|
+
* Each was MEASURED against the old reader over a shared corpus, which the
|
|
197
|
+
* differential test re-runs; the equivalence is not argued from documentation.
|
|
198
|
+
*
|
|
199
|
+
* · `schema: 'core'` + `resolveKnownTags: false` — WITHOUT THIS, THE SWAP
|
|
200
|
+
* WOULD HAVE WEAKENED THE GUARD. `js-yaml` v5's default CORE schema does
|
|
201
|
+
* not carry the YAML 1.1 tags, so `!!timestamp`, `!!binary`, `!!set`,
|
|
202
|
+
* `!!omap`, `!!pairs` and any unknown `!custom` tag THREW — the document
|
|
203
|
+
* was unparseable and the guard refused. The `yaml` package resolves them
|
|
204
|
+
* by default, so the same document would have parsed and the guard would
|
|
205
|
+
* have gone on to allow an edit it previously refused. Found by an
|
|
206
|
+
* independent council review (openai/codex-default, 2026-10-01) and
|
|
207
|
+
* confirmed by running both readers: six tagged inputs, `js-yaml` throws on
|
|
208
|
+
* all six, default `yaml` returns a value for all six.
|
|
209
|
+
* · A WARNING IS A REFUSAL. `yaml` reports an unresolvable tag as a warning
|
|
210
|
+
* and keeps parsing where `js-yaml` throws, so treating warnings as success
|
|
211
|
+
* would re-open the same hole one tag at a time. `parseDocument` is used
|
|
212
|
+
* rather than `parse` precisely to see them.
|
|
213
|
+
* · NULLISH IS UNPARSEABLE. `js-yaml` threw on an empty document and returned
|
|
214
|
+
* `null` for a value-less one (`~`, `null`); both landed on refusal. `yaml`
|
|
215
|
+
* returns `null` for all three instead of throwing on the first, so without
|
|
216
|
+
* this collapse an EMPTIED settings file would arrive at the caller as a
|
|
217
|
+
* parsed document with no keys — the one shape that turns "I cannot read
|
|
218
|
+
* this" into "nothing changed".
|
|
219
|
+
*
|
|
220
|
+
* · `merge: false` — PINNED, NOT FIXING AN OBSERVED DIFFERENCE. The `yaml`
|
|
221
|
+
* package documents `merge` as defaulting to the document's YAML VERSION:
|
|
222
|
+
* true for 1.1, false for 1.2. A second review round (openai/codex-default)
|
|
223
|
+
* flagged that a `%YAML 1.1` directive could therefore re-enable merge
|
|
224
|
+
* resolution past the schema pin, which would expose keys the old reader
|
|
225
|
+
* left nested under a literal `<<`. Measured, and it does NOT reproduce
|
|
226
|
+
* here — under `schema: 'core'` a `%YAML 1.1` document reads
|
|
227
|
+
* `{"personal":{"<<":{…}}}` identically with and without this option, same
|
|
228
|
+
* as `js-yaml`. It is set anyway because the cost is a word and the finding
|
|
229
|
+
* named a real documented coupling between two options: a future default
|
|
230
|
+
* cannot flip it silently. An option set without an observed failure behind
|
|
231
|
+
* it is said so rather than implied.
|
|
232
|
+
*
|
|
233
|
+
* A merge key (`<<: *anchor`) was raised as a difference by the other seat and
|
|
234
|
+
* is NOT one: both readers leave `<<` literal at these versions, with and
|
|
235
|
+
* without a version directive. The same differential corpus pins both forms, so
|
|
236
|
+
* the question is settled by a reading rather than re-litigated from
|
|
237
|
+
* documentation next time.
|
|
238
|
+
*/
|
|
239
|
+
export function parseSettingsDoc(text: string, rel: string): unknown | null {
|
|
240
|
+
if (rel.endsWith('.json')) {
|
|
241
|
+
try {
|
|
242
|
+
return (JSON.parse(text) as unknown) ?? null;
|
|
243
|
+
} catch {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
const doc = parseYamlDocument(text, { schema: 'core', resolveKnownTags: false, merge: false });
|
|
249
|
+
if (doc.errors.length > 0 || doc.warnings.length > 0) return null;
|
|
250
|
+
return (doc.toJS() as unknown) ?? null;
|
|
251
|
+
} catch {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Dotted paths whose value differs between two settings documents. */
|
|
257
|
+
export function changedKeys(before: unknown, after: unknown): string[] {
|
|
258
|
+
const a = leafPaths(before);
|
|
259
|
+
const b = leafPaths(after);
|
|
260
|
+
const out = new Set<string>();
|
|
261
|
+
for (const [k, v] of b) if (a.get(k) !== v) out.add(k);
|
|
262
|
+
for (const k of a.keys()) if (!b.has(k)) out.add(k);
|
|
263
|
+
return [...out].sort();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* The class index, read from the shipped contract. `null` when it cannot be
|
|
268
|
+
* read AT ALL, which the caller treats as fail-closed.
|
|
269
|
+
*
|
|
270
|
+
* Not cached: the file is small, and a cache would keep a stale fence alive
|
|
271
|
+
* across an upgrade that reclassified a key — the same reasoning the server's
|
|
272
|
+
* own reader states for the same file.
|
|
273
|
+
*/
|
|
274
|
+
export function readClassIndex(packageRoot: string): Map<string, SettingsClass> | null {
|
|
275
|
+
try {
|
|
276
|
+
const text = fs.readFileSync(path.join(packageRoot, SETTINGS_CLASSES_RELATIVE), 'utf-8');
|
|
277
|
+
const index = buildSettingsClassIndex(parseSettingsClassRows(text));
|
|
278
|
+
return index.size === 0 ? null : index;
|
|
279
|
+
} catch {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* The guarded subset of a change list.
|
|
286
|
+
*
|
|
287
|
+
* A key is guarded when its nearest classified ancestor is C, and ALSO when
|
|
288
|
+
* nothing on its path is classified at all — the same per-key refusal
|
|
289
|
+
* `settings:set` and the GUI write route already apply, reached here through
|
|
290
|
+
* the same shared classifier rather than a second copy of the rule.
|
|
291
|
+
*/
|
|
292
|
+
export function guardedKeys(index: ReadonlyMap<string, SettingsClass> | null, keys: readonly string[]): string[] {
|
|
293
|
+
if (index === null) return [...keys];
|
|
294
|
+
return keys.filter((k) => {
|
|
295
|
+
const cls = classOfPath(index, k);
|
|
296
|
+
return cls === 'C' || cls === undefined;
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
102
300
|
/**
|
|
103
301
|
* Count allowlist entries in a blob.
|
|
104
302
|
*
|
|
@@ -167,6 +365,89 @@ export interface Decision {
|
|
|
167
365
|
}
|
|
168
366
|
|
|
169
367
|
/** Decide from the cumulative session total for one allowlist file. */
|
|
368
|
+
/**
|
|
369
|
+
* The refusal reason for a class-C settings edit, or `null` to allow.
|
|
370
|
+
*
|
|
371
|
+
* WHAT THIS FENCES, and what it deliberately does not. The unit is the KEY, not
|
|
372
|
+
* the file: a Class A key stays agent-writable through this path exactly as it
|
|
373
|
+
* is through `settings:set`, and fencing the whole file would make an ordinary
|
|
374
|
+
* preference edit need a human. Only a key the contract classifies C — or one
|
|
375
|
+
* nothing on its path classifies at all, which is the same fail-closed default
|
|
376
|
+
* the CLI writer applies — is refused.
|
|
377
|
+
*
|
|
378
|
+
* THE UNPARSEABLE CASES REFUSE, both of them, and for the same reason. A
|
|
379
|
+
* contract this guard cannot read leaves it with no way to tell a C key from an
|
|
380
|
+
* A key; a resulting document it cannot parse leaves it with no key list at
|
|
381
|
+
* all. Allowing either would mean the fence is lifted by making one file
|
|
382
|
+
* unreadable for the length of one tool call, which is a bypass with no
|
|
383
|
+
* authorisation step in it.
|
|
384
|
+
*
|
|
385
|
+
* WHAT IT CANNOT SEE: an edit applied through a shell redirect rather than an
|
|
386
|
+
* edit tool — `EDIT_TOOLS` is the corpus, and the shell shapes are
|
|
387
|
+
* `block_plumbing_writes`' subject, not this one.
|
|
388
|
+
*/
|
|
389
|
+
export function classCVerdict(
|
|
390
|
+
ti: JsonObject,
|
|
391
|
+
on_disk: string | null,
|
|
392
|
+
rel_path: string,
|
|
393
|
+
index: ReadonlyMap<string, SettingsClass> | null,
|
|
394
|
+
): string | null {
|
|
395
|
+
const before = on_disk === null ? null : parseSettingsDoc(on_disk, rel_path);
|
|
396
|
+
|
|
397
|
+
const content = ti['content'];
|
|
398
|
+
const oldStr = ti['old_string'];
|
|
399
|
+
const newStr = ti['new_string'];
|
|
400
|
+
let afterText: string | null = null;
|
|
401
|
+
if (typeof content === 'string') {
|
|
402
|
+
afterText = content;
|
|
403
|
+
} else if (typeof oldStr === 'string' && typeof newStr === 'string' && on_disk !== null) {
|
|
404
|
+
if (!on_disk.includes(oldStr)) return null; // the edit will not apply
|
|
405
|
+
// `replace_all` is the host's own flag and it changes WHICH text the
|
|
406
|
+
// edit produces. Modelling only the first occurrence let a
|
|
407
|
+
// `replace_all` edit whose SECOND occurrence is the Class C one pass
|
|
408
|
+
// this guard while the real edit changed it — the guard evaluating a
|
|
409
|
+
// different edit from the one executed. Reported by an independent
|
|
410
|
+
// review before this landed.
|
|
411
|
+
const all = ti['replace_all'];
|
|
412
|
+
if (all !== undefined && typeof all !== 'boolean') {
|
|
413
|
+
return (
|
|
414
|
+
`${rel_path}: this edit carries a \`replace_all\` value the guard cannot ` +
|
|
415
|
+
'interpret, so the text it would produce is unknown and no key can be ' +
|
|
416
|
+
'cleared. Re-send it as a plain edit, or write the change through ' +
|
|
417
|
+
'`agent-config settings:set`.'
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
afterText = all === true ? on_disk.split(oldStr).join(newStr) : on_disk.replace(oldStr, newStr);
|
|
421
|
+
}
|
|
422
|
+
if (afterText === null) return null;
|
|
423
|
+
|
|
424
|
+
const after = parseSettingsDoc(afterText, rel_path);
|
|
425
|
+
if (after === null) {
|
|
426
|
+
return (
|
|
427
|
+
`${rel_path}: the result of this edit does not parse as settings, so no key ` +
|
|
428
|
+
'list can be derived and no key can be cleared. Fix the syntax, or write the ' +
|
|
429
|
+
'change through `agent-config settings:set`, which refuses a Class C key by name.'
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const guarded = guardedKeys(index, changedKeys(before, after));
|
|
434
|
+
if (guarded.length === 0) return null;
|
|
435
|
+
|
|
436
|
+
const unreadable =
|
|
437
|
+
index === null
|
|
438
|
+
? ' The class contract could not be read, so EVERY changed key is treated as ' +
|
|
439
|
+
'guarded — that is the fail-closed direction, not a classification.'
|
|
440
|
+
: '';
|
|
441
|
+
return (
|
|
442
|
+
`${rel_path}: this edit changes ${String(guarded.length)} guarded settings key(s) — ` +
|
|
443
|
+
`${guarded.slice(0, 5).join(', ')}${guarded.length > 5 ? ', …' : ''}.` +
|
|
444
|
+
unreadable +
|
|
445
|
+
' A Class C key is a policy dial (spend ceiling, allowlist, gate switch, hooks) and ' +
|
|
446
|
+
'is a human edit by contract: docs/contracts/settings-classes.md. Every other key in ' +
|
|
447
|
+
'this file stays writable.'
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
170
451
|
export function decide(kind: ConfigKind, rel_path: string, session_total: number, added: number): Decision {
|
|
171
452
|
if (kind === null || added <= 0) {
|
|
172
453
|
return { action: 'allow', reason: '' };
|
|
@@ -292,6 +573,15 @@ export function main(): number {
|
|
|
292
573
|
} catch {
|
|
293
574
|
on_disk = null;
|
|
294
575
|
}
|
|
576
|
+
if (kind === 'class-c') {
|
|
577
|
+
const rel_c = path.relative(root, abs) || p;
|
|
578
|
+
const pkg = findPackageRoot(_HERE);
|
|
579
|
+
const verdict = classCVerdict(ti, on_disk, rel_c, pkg === null ? null : readClassIndex(pkg));
|
|
580
|
+
if (verdict === null) continue;
|
|
581
|
+
process.stderr.write(`block-config-weakening: BLOCKED — ${verdict}\n`);
|
|
582
|
+
return EXIT_BLOCK;
|
|
583
|
+
}
|
|
584
|
+
|
|
295
585
|
const added = added_entries(ti, on_disk);
|
|
296
586
|
if (added <= 0) {
|
|
297
587
|
continue;
|
|
@@ -49,6 +49,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
49
49
|
import * as path from 'node:path';
|
|
50
50
|
|
|
51
51
|
import { is_kernel_rule } from '../_lib/kernel_rules.js';
|
|
52
|
+
import { shellWriteTarget } from '../_lib/shell_write_shapes.js';
|
|
52
53
|
import { EDIT_TOOLS } from '../minimal_safe_diff_hook.js';
|
|
53
54
|
import { COMMAND_TOOLS } from '../before_complete_hook.js';
|
|
54
55
|
import { readHookStdin } from './hook_stdin.js';
|
|
@@ -133,87 +134,17 @@ export function targets_kernel_rule(filePath: string): string | null {
|
|
|
133
134
|
return basename.replace(/\.md$/, '');
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
/** In-place mutators that name their target as a plain argument. */
|
|
137
|
-
const _MUTATOR_VERBS: ReadonlySet<string> = new Set([
|
|
138
|
-
'sed',
|
|
139
|
-
'tee',
|
|
140
|
-
'truncate',
|
|
141
|
-
'rm',
|
|
142
|
-
'shred',
|
|
143
|
-
]);
|
|
144
|
-
/** Verbs whose LAST positional argument is the destination. */
|
|
145
|
-
const _DEST_LAST_VERBS: ReadonlySet<string> = new Set(['mv', 'cp', 'install', 'rsync']);
|
|
146
|
-
|
|
147
137
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
138
|
+
* The kernel rule a command WRITES, or null.
|
|
139
|
+
*
|
|
140
|
+
* The shape catalogue moved to `_lib/shell_write_shapes.ts` when
|
|
141
|
+
* `block_plumbing_writes.ts` needed the same shapes over a different file set
|
|
142
|
+
* (road-to-a-kernel-that-guards-its-plumbing 1.2). Behaviour here is unchanged:
|
|
143
|
+
* the narrowness, the reads-stay-allowed rule and the known-open interpreter
|
|
144
|
+
* residual are all properties of that shared module now, stated in its header.
|
|
152
145
|
*/
|
|
153
146
|
function _bash_targets_kernel_rule(command: string): string | null {
|
|
154
|
-
|
|
155
|
-
const tokens = command.split(/\s+/).filter((t) => t.length > 0);
|
|
156
|
-
const stripped = tokens.map((t) => t.replace(/^['"]|['"]$/g, ''));
|
|
157
|
-
const ruleOf = (t: string): string | null => targets_kernel_rule(t);
|
|
158
|
-
if (!stripped.some((t) => ruleOf(t) !== null)) {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// 1. Redirection into the path: `> p`, `>> p`, `>p`, `>>p`.
|
|
163
|
-
for (let i = 0; i < stripped.length; i += 1) {
|
|
164
|
-
const tok = stripped[i] as string;
|
|
165
|
-
const inline = /^>{1,2}(.+)$/.exec(tok);
|
|
166
|
-
if (inline) {
|
|
167
|
-
const r = ruleOf(inline[1] as string);
|
|
168
|
-
if (r !== null) {
|
|
169
|
-
return r;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (tok === '>' || tok === '>>') {
|
|
173
|
-
const next = stripped[i + 1];
|
|
174
|
-
if (typeof next === 'string') {
|
|
175
|
-
const r = ruleOf(next);
|
|
176
|
-
if (r !== null) {
|
|
177
|
-
return r;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// 2. A mutator verb anywhere in the pipeline, with the path as an argument.
|
|
184
|
-
// `sed` only counts in its in-place form — `sed 's/x/y/' file` prints.
|
|
185
|
-
const verbs = new Set<string>();
|
|
186
|
-
let prevWasSeparator = true;
|
|
187
|
-
for (const tok of stripped) {
|
|
188
|
-
if (['&&', '||', ';', '|'].includes(tok)) {
|
|
189
|
-
prevWasSeparator = true;
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
if (prevWasSeparator && !tok.startsWith('-')) {
|
|
193
|
-
verbs.add(path.basename(tok));
|
|
194
|
-
prevWasSeparator = false;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
const sedInPlace = verbs.has('sed') && stripped.some((t) => /^-i/.test(t));
|
|
198
|
-
for (const verb of verbs) {
|
|
199
|
-
if (verb === 'sed' && !sedInPlace) {
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
if (_MUTATOR_VERBS.has(verb)) {
|
|
203
|
-
const hit = stripped.map(ruleOf).find((r) => r !== null);
|
|
204
|
-
if (hit !== undefined && hit !== null) {
|
|
205
|
-
return hit;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (_DEST_LAST_VERBS.has(verb)) {
|
|
209
|
-
const last = stripped[stripped.length - 1] as string;
|
|
210
|
-
const r = ruleOf(last);
|
|
211
|
-
if (r !== null) {
|
|
212
|
-
return r;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return null;
|
|
147
|
+
return shellWriteTarget(command, targets_kernel_rule);
|
|
217
148
|
}
|
|
218
149
|
|
|
219
150
|
/**
|