@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
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
*
|
|
10
10
|
* 1. **No array indices.** Pointers MUST target named object keys only.
|
|
11
11
|
* `/hooks/PostToolUse` is valid; `/hooks/PostToolUse/0` is not.
|
|
12
|
-
* 2. **Arrays carry a
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* 2. **Arrays carry a discriminator, and which one depends on who owns
|
|
13
|
+
* the list.** A list this package owns outright records the SHA-256 of
|
|
14
|
+
* the contents the install wrote, so uninstall identifies the owned
|
|
15
|
+
* elements by content rather than position. A list it merely APPENDS to —
|
|
16
|
+
* a host's `hooks.<event>`, shared with every other agent package the
|
|
17
|
+
* consumer installed — records an `entry_signature` instead: uninstall
|
|
18
|
+
* then filters that list rather than claiming it. Recording a hash there
|
|
19
|
+
* was the defect; it made uninstall either delete a neighbour's entries
|
|
20
|
+
* or, once a neighbour had appended, refuse and leave ours behind.
|
|
16
21
|
*
|
|
17
22
|
* `value_hash` reproduces Python's canonical
|
|
18
23
|
* `json.dumps(value, sort_keys=True, separators=(",", ":"))` output
|
|
@@ -22,6 +27,8 @@
|
|
|
22
27
|
|
|
23
28
|
import { createHash } from "node:crypto";
|
|
24
29
|
|
|
30
|
+
import { HOOK_SIGNATURES, isManagedEntry } from "./host_hook_merge.js";
|
|
31
|
+
|
|
25
32
|
type JsonValue =
|
|
26
33
|
| null
|
|
27
34
|
| boolean
|
|
@@ -172,6 +179,23 @@ export function value_hash(value: unknown): string {
|
|
|
172
179
|
export interface PointerEntry {
|
|
173
180
|
json_pointer: string;
|
|
174
181
|
value_hash: string | null;
|
|
182
|
+
/**
|
|
183
|
+
* Set when the pointer targets a SHARED array this package appends to
|
|
184
|
+
* rather than owns — a host's `hooks.<event>` list.
|
|
185
|
+
*
|
|
186
|
+
* Recording `value_hash` for such an array claims the whole list, and both
|
|
187
|
+
* outcomes of that claim are wrong at uninstall: an untouched list is
|
|
188
|
+
* deleted wholesale, taking a neighbour's entries with it, and a list a
|
|
189
|
+
* neighbour appended to reports `drift` and leaves OUR entries behind. With
|
|
190
|
+
* a signature, subtraction filters the array instead: entries carrying the
|
|
191
|
+
* signature go, everything else stays, and the key is removed only once the
|
|
192
|
+
* list is empty.
|
|
193
|
+
*
|
|
194
|
+
* `value_hash` is null whenever this is set — the two are alternatives, and
|
|
195
|
+
* a hash of a list other packages may legitimately have changed is not a
|
|
196
|
+
* drift signal, it is a false one.
|
|
197
|
+
*/
|
|
198
|
+
entry_signature?: string;
|
|
175
199
|
}
|
|
176
200
|
|
|
177
201
|
export interface MergeEntry extends PointerEntry {
|
|
@@ -187,6 +211,12 @@ function _is_plain_object(value: unknown): value is Record<string, unknown> {
|
|
|
187
211
|
export interface CollectPointersOptions {
|
|
188
212
|
prefix?: string;
|
|
189
213
|
include_arrays?: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Content signature identifying this package's entries inside a shared
|
|
216
|
+
* array. When set, an array pointer records the signature instead of a
|
|
217
|
+
* whole-list hash (see `PointerEntry.entry_signature`).
|
|
218
|
+
*/
|
|
219
|
+
entry_signature?: string;
|
|
190
220
|
}
|
|
191
221
|
|
|
192
222
|
/**
|
|
@@ -208,6 +238,7 @@ export function collect_pointers(
|
|
|
208
238
|
): PointerEntry[] {
|
|
209
239
|
const prefix = options.prefix ?? "";
|
|
210
240
|
const include_arrays = options.include_arrays ?? true;
|
|
241
|
+
const entry_signature = options.entry_signature ?? "";
|
|
211
242
|
const entries: PointerEntry[] = [];
|
|
212
243
|
for (const [key, value] of Object.entries(overlay)) {
|
|
213
244
|
const pointer = `${prefix}/${_escape_segment(String(key))}`;
|
|
@@ -219,14 +250,29 @@ export function collect_pointers(
|
|
|
219
250
|
entries.push({ json_pointer: pointer, value_hash: null });
|
|
220
251
|
} else {
|
|
221
252
|
entries.push(
|
|
222
|
-
...collect_pointers(value, {
|
|
253
|
+
...collect_pointers(value, {
|
|
254
|
+
prefix: pointer,
|
|
255
|
+
include_arrays,
|
|
256
|
+
entry_signature,
|
|
257
|
+
}),
|
|
223
258
|
);
|
|
224
259
|
}
|
|
225
260
|
} else if (Array.isArray(value)) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
261
|
+
// Only the host's shared hook lists are appended to; every other array
|
|
262
|
+
// in the same overlay — `mcpServers.*.args`, for one — this package
|
|
263
|
+
// still owns outright and keeps hashing.
|
|
264
|
+
if (entry_signature !== "" && pointer.startsWith("/hooks/")) {
|
|
265
|
+
entries.push({
|
|
266
|
+
json_pointer: pointer,
|
|
267
|
+
value_hash: null,
|
|
268
|
+
entry_signature,
|
|
269
|
+
});
|
|
270
|
+
} else {
|
|
271
|
+
entries.push({
|
|
272
|
+
json_pointer: pointer,
|
|
273
|
+
value_hash: include_arrays ? value_hash(value) : null,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
230
276
|
} else {
|
|
231
277
|
entries.push({ json_pointer: pointer, value_hash: null });
|
|
232
278
|
}
|
|
@@ -252,11 +298,16 @@ export function build_merge_entries(
|
|
|
252
298
|
file_label: string,
|
|
253
299
|
overlay: Record<string, unknown>,
|
|
254
300
|
): MergeEntry[] {
|
|
255
|
-
const pointers = collect_pointers(overlay
|
|
301
|
+
const pointers = collect_pointers(overlay, {
|
|
302
|
+
entry_signature: HOOK_SIGNATURES[file_label] ?? "",
|
|
303
|
+
});
|
|
256
304
|
return pointers.map((entry) => ({
|
|
257
305
|
file: file_label,
|
|
258
306
|
json_pointer: entry.json_pointer,
|
|
259
307
|
value_hash: entry.value_hash,
|
|
308
|
+
...(entry.entry_signature === undefined
|
|
309
|
+
? {}
|
|
310
|
+
: { entry_signature: entry.entry_signature }),
|
|
260
311
|
}));
|
|
261
312
|
}
|
|
262
313
|
|
|
@@ -304,6 +355,8 @@ export interface SubtractWarning {
|
|
|
304
355
|
export interface SubtractEntry {
|
|
305
356
|
json_pointer: string;
|
|
306
357
|
value_hash?: string | null;
|
|
358
|
+
/** See `PointerEntry.entry_signature` — filters a shared array in place. */
|
|
359
|
+
entry_signature?: string;
|
|
307
360
|
}
|
|
308
361
|
|
|
309
362
|
/**
|
|
@@ -354,7 +407,36 @@ export function subtract_pointers(
|
|
|
354
407
|
continue;
|
|
355
408
|
}
|
|
356
409
|
const [parent, leaf] = nav;
|
|
357
|
-
|
|
410
|
+
const signature = entry.entry_signature ?? "";
|
|
411
|
+
if (signature !== "") {
|
|
412
|
+
const current = parent[leaf];
|
|
413
|
+
if (!Array.isArray(current)) {
|
|
414
|
+
warnings.push({
|
|
415
|
+
pointer,
|
|
416
|
+
reason: "missing",
|
|
417
|
+
expected_hash: null,
|
|
418
|
+
actual_hash: null,
|
|
419
|
+
});
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
// A shared list: drop only the entries carrying our signature, keep a
|
|
423
|
+
// neighbour's in order and byte-identical, and remove the key only once
|
|
424
|
+
// nothing of ours is left in it.
|
|
425
|
+
const kept = current.filter((item) => !isManagedEntry(item, signature));
|
|
426
|
+
if (kept.length === current.length) {
|
|
427
|
+
warnings.push({
|
|
428
|
+
pointer,
|
|
429
|
+
reason: "missing",
|
|
430
|
+
expected_hash: null,
|
|
431
|
+
actual_hash: null,
|
|
432
|
+
});
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
if (kept.length > 0) {
|
|
436
|
+
parent[leaf] = kept;
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
} else if (expected !== null) {
|
|
358
440
|
const actual = value_hash(parent[leaf]);
|
|
359
441
|
if (actual !== expected) {
|
|
360
442
|
warnings.push({
|
|
@@ -1,20 +1,65 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `lean_projection.mode` — ONE definition of what the three modes mean
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
2
|
+
* `lean_projection.mode` — ONE definition of what the three modes mean, and
|
|
3
|
+
* since step 1.2 of `road-to-a-rule-carrier-that-works-outside-the-repo`, ONE
|
|
4
|
+
* reader that produces it.
|
|
5
|
+
*
|
|
6
|
+
* ── What this module used to be, and why that was not enough ──
|
|
7
|
+
*
|
|
8
|
+
* It owned the NORMALISATION and left each caller its own READER: the projector
|
|
9
|
+
* (`condense.ts`) resolved the value with a real YAML parse over the full
|
|
10
|
+
* settings cascade; the delivery concern (`hooks/rule_inject_hook.ts`) resolved
|
|
11
|
+
* it with an indentation-shaped read of `<cwd>/.agent-settings.yml` alone. The
|
|
12
|
+
* header argued that two readers were unavoidable and that two *normalisations*
|
|
13
|
+
* were the only thing worth preventing.
|
|
14
|
+
*
|
|
15
|
+
* Measured on 2026-10-02, that split was not a stylistic difference — it was a
|
|
16
|
+
* disagreement about WHICH FILE. The installer writes settings to
|
|
17
|
+
* `<root>/agents/settings/.agent-settings.yml` (`agent_settings.ts`'s canonical
|
|
18
|
+
* write target; `install.ts:4108`). The concern read `<root>/.agent-settings.yml`,
|
|
19
|
+
* the LEGACY location, and nothing else. On a normal install the concern
|
|
20
|
+
* therefore read a file that does not exist, got `''`, normalised it to
|
|
21
|
+
* `eager-all`, and closed its own gate — while the projector, reading the
|
|
22
|
+
* canonical file, had written thin stubs. That is the pointer arm the delivery
|
|
23
|
+
* mode exists to replace, reached by configuration rather than by choice, and
|
|
24
|
+
* it is a SECOND independent cause of the silence step 1.1 repaired: a consumer
|
|
25
|
+
* that fixed the package root alone would still have received nothing.
|
|
26
|
+
*
|
|
27
|
+
* The user-global layer was invisible to the concern for the same reason, which
|
|
28
|
+
* matters more than it sounds: ADR-020 installs are global-only, so for those
|
|
29
|
+
* consumers the ONLY layer carrying a mode is one the concern never opened.
|
|
30
|
+
*
|
|
31
|
+
* ── D3: one resolver, not a parity test between three ──
|
|
32
|
+
*
|
|
33
|
+
* The roadmap's D3 records the choice and the reason — a parity test keeps
|
|
34
|
+
* three readers that can drift again, and this module already existed to be the
|
|
35
|
+
* one. `resolveLeanProjection` below is that resolver. It reads the layers in
|
|
36
|
+
* the order `load_agent_settings` defines (template base, user-global,
|
|
37
|
+
* project), through `project_settings_path`, which prefers the canonical file
|
|
38
|
+
* and falls back to the legacy one, so a hand-edited root file still works.
|
|
39
|
+
*
|
|
40
|
+
* ── Why the template path is passed in rather than resolved ──
|
|
41
|
+
*
|
|
42
|
+
* `agent_settings.default_template_path()` derives the package root from
|
|
43
|
+
* `import.meta.url` three directories up. That is correct for a module at
|
|
44
|
+
* `<pkg>/src/scripts/_lib/`; inside the composed hook bundle `import.meta.url`
|
|
45
|
+
* is `<pkg>/dist/hooks/dispatch.js`, so the same arithmetic yields the PARENT
|
|
46
|
+
* of the package and the template read misses. Verified in the built bundle,
|
|
47
|
+
* not inferred. With no template the base layer is `{}` and an unconfigured
|
|
48
|
+
* consumer resolves to `eager-all` — the silence again, one layer lower. So a
|
|
49
|
+
* caller that knows the real package root (the carrier does: the dispatcher
|
|
50
|
+
* passes it) hands it over, and the resolver reads the template from there.
|
|
51
|
+
*
|
|
52
|
+
* ── What has NOT changed ──
|
|
53
|
+
*
|
|
54
|
+
* Anything unrecognised — absent key, typo, `null`, a non-string — is still
|
|
55
|
+
* `eager-all`: the parser fallback, which is NOT the value the template ships
|
|
56
|
+
* (see the type below), because a mode nobody can spell must never silently
|
|
57
|
+
* thin the standing corpus. That fallback now fires only when no layer carried
|
|
58
|
+
* a value at all, rather than whenever the concern looked in the wrong place.
|
|
17
59
|
*/
|
|
60
|
+
import * as path from 'node:path';
|
|
61
|
+
|
|
62
|
+
import { load_agent_settings } from './agent_settings.js';
|
|
18
63
|
|
|
19
64
|
/**
|
|
20
65
|
* The three projection shapes, and the two different defaults they answer to.
|
|
@@ -180,3 +225,218 @@ export function describeDroppedHosts(res: LeanProjectionHosts): string[] {
|
|
|
180
225
|
export function thinsHost(mode: LeanProjectionMode, hosts: readonly string[], hostId: string): boolean {
|
|
181
226
|
return writesThinFiles(mode) && hosts.includes(hostId);
|
|
182
227
|
}
|
|
228
|
+
|
|
229
|
+
export interface ResolvedLeanProjection {
|
|
230
|
+
readonly mode: LeanProjectionMode;
|
|
231
|
+
readonly hosts: LeanProjectionHosts;
|
|
232
|
+
/**
|
|
233
|
+
* Was `lean_projection.mode` set on a layer the USER controls — user-global,
|
|
234
|
+
* project, or project-local — rather than inherited from the shipped
|
|
235
|
+
* template?
|
|
236
|
+
*
|
|
237
|
+
* THE DISTINCTION IS NOT A REFINEMENT, IT IS A SAFETY BOUNDARY, and it is
|
|
238
|
+
* the one `road-to-an-installed-layer-that-is-thinned` names in its Context:
|
|
239
|
+
* the shipped template already says `mode: delivery`
|
|
240
|
+
* (`src/config/agent-settings.template.yml:212-214`), so the moment the
|
|
241
|
+
* INSTALLER resolves the mode through this resolver, the template value
|
|
242
|
+
* alone would thin every consumer's `~/.claude/rules` — a default flip
|
|
243
|
+
* arriving as a side effect of wiring a reader, with nobody deciding it.
|
|
244
|
+
*
|
|
245
|
+
* Whether that default flips is owner-reserved (that roadmap's blocker
|
|
246
|
+
* `default-flip-of-the-installed-layer`, decision D4). So the installer must
|
|
247
|
+
* be able to ask a question `mode` cannot answer: not "what is the mode" but
|
|
248
|
+
* "did a human ask for this". That is this flag, and it is why it reports
|
|
249
|
+
* provenance rather than a value.
|
|
250
|
+
*
|
|
251
|
+
* `false` whenever no layer the user controls carries the key — including
|
|
252
|
+
* when `mode` reads `delivery` from the template, which is exactly the case
|
|
253
|
+
* that must NOT be read as consent.
|
|
254
|
+
*/
|
|
255
|
+
readonly modeExplicit: boolean;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export interface ResolveOptions {
|
|
259
|
+
/** Project tree whose settings cascade is read. */
|
|
260
|
+
readonly projectRoot?: string | null;
|
|
261
|
+
/** Explicit settings file, overriding `projectRoot`. Tests and `condense` pin this. */
|
|
262
|
+
readonly settingsPath?: string | null;
|
|
263
|
+
/** Install root carrying `src/config/agent-settings.template.yml`. */
|
|
264
|
+
readonly packageRoot?: string | null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* THE resolver. Every surface that asks "which delivery mode" calls this.
|
|
269
|
+
*
|
|
270
|
+
* Tolerant like everything else on a hook path: `load_agent_settings` answers
|
|
271
|
+
* with defaults on an unreadable or malformed file and never throws, and the
|
|
272
|
+
* normalisers above turn anything unrecognised into the safe value. A caller
|
|
273
|
+
* on a hot path pays ONE cascade read per prompt; `modeExplicit` is a lazy
|
|
274
|
+
* getter, so the second, template-isolated read happens only for a caller that
|
|
275
|
+
* actually reads provenance — which today is the installer and nothing else.
|
|
276
|
+
*/
|
|
277
|
+
export function resolveLeanProjection(opts: ResolveOptions = {}): ResolvedLeanProjection {
|
|
278
|
+
// The LEGACY root path, deliberately, and not `project_settings_path`'s
|
|
279
|
+
// either-or pick. `load_agent_settings` expands whatever it is given into
|
|
280
|
+
// `[the file, <its dir>/agents/settings/.agent-settings.yml, <its dir>/
|
|
281
|
+
// agents/settings/.agent-settings.local.yml]` and merges them deepest-wins,
|
|
282
|
+
// so handing it the root path reads BOTH the legacy and the canonical file
|
|
283
|
+
// — which is strictly more than picking one, and is what a tree carrying
|
|
284
|
+
// both should resolve to. It also keeps one export out of this module's
|
|
285
|
+
// import list, which is runtime bytes in the composed hook bundle.
|
|
286
|
+
const file =
|
|
287
|
+
opts.settingsPath ?? path.join(opts.projectRoot ?? process.cwd(), '.agent-settings.yml');
|
|
288
|
+
const tpl =
|
|
289
|
+
opts.packageRoot == null
|
|
290
|
+
? null
|
|
291
|
+
: path.join(opts.packageRoot, 'src', 'config', 'agent-settings.template.yml');
|
|
292
|
+
let lean: unknown;
|
|
293
|
+
try {
|
|
294
|
+
lean = load_agent_settings(
|
|
295
|
+
tpl === null ? { project_path: file } : { project_path: file, template_path: tpl },
|
|
296
|
+
)['lean_projection'];
|
|
297
|
+
} catch {
|
|
298
|
+
/* a settings layer nothing can read must never fail a turn */
|
|
299
|
+
}
|
|
300
|
+
const obj = typeof lean === 'object' && lean !== null && !Array.isArray(lean) ? lean : {};
|
|
301
|
+
const o = obj as Record<string, unknown>;
|
|
302
|
+
return {
|
|
303
|
+
mode: normalizeLeanProjectionMode(o['mode'] ?? ''),
|
|
304
|
+
hosts: resolveLeanProjectionHosts(o['hosts']),
|
|
305
|
+
// LAZY, and the hot path is the reason. Provenance needs a SECOND,
|
|
306
|
+
// template-isolated cascade, and only the installer reads it — the
|
|
307
|
+
// delivery concern on `user_prompt_submit` destructures `{ mode, hosts }`
|
|
308
|
+
// and discards this field, so computing it eagerly doubled the per-prompt
|
|
309
|
+
// settings read for an answer nobody asked for. A getter keeps the
|
|
310
|
+
// field's shape (`readonly modeExplicit: boolean`) and charges only the
|
|
311
|
+
// caller that touches it.
|
|
312
|
+
get modeExplicit(): boolean {
|
|
313
|
+
return rawExplicitLeanProjectionMode(opts) !== '';
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* A path no tree contains, so `template_defaults` contributes nothing.
|
|
320
|
+
*
|
|
321
|
+
* This is the mechanism `load_agent_settings` documents for the purpose —
|
|
322
|
+
* "a test or tool that pins every other input can pin the defaults base too,
|
|
323
|
+
* and point it at a nonexistent file to isolate the cascade" — used here for a
|
|
324
|
+
* tool rather than a test. It is a reserved device filename on every platform
|
|
325
|
+
* this package runs on and is never created, so the read fails and the loader's
|
|
326
|
+
* own tolerance turns it into `{}`.
|
|
327
|
+
*
|
|
328
|
+
* The alternative — re-reading the YAML layers by hand — was rejected because
|
|
329
|
+
* it would be a SECOND reader of the same key, which is the precise defect step
|
|
330
|
+
* 1.2 of the carrier roadmap existed to remove. Isolating the base keeps one
|
|
331
|
+
* reader and changes only which layers it is given.
|
|
332
|
+
*/
|
|
333
|
+
const NO_TEMPLATE_LAYER = path.join(path.sep, 'dev', 'null', 'agent-config-absent-template.yml');
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* The RAW `lean_projection.mode` string from the user-controlled layers only,
|
|
337
|
+
* or `''` when no such layer carries it.
|
|
338
|
+
*
|
|
339
|
+
* Raw and un-normalised on purpose: {@link normalizeLeanProjectionMode} maps
|
|
340
|
+
* everything unrecognised — `''` included — onto `eager-all`, so a normalised
|
|
341
|
+
* answer cannot tell "the user chose eager-all" from "the user chose nothing".
|
|
342
|
+
* Provenance needs exactly that distinction, so it has to be read before the
|
|
343
|
+
* normaliser runs.
|
|
344
|
+
*/
|
|
345
|
+
export function rawExplicitLeanProjectionMode(opts: ResolveOptions = {}): string {
|
|
346
|
+
const file =
|
|
347
|
+
opts.settingsPath ?? path.join(opts.projectRoot ?? process.cwd(), '.agent-settings.yml');
|
|
348
|
+
let lean: unknown;
|
|
349
|
+
try {
|
|
350
|
+
lean = load_agent_settings({ project_path: file, template_path: NO_TEMPLATE_LAYER })[
|
|
351
|
+
'lean_projection'
|
|
352
|
+
];
|
|
353
|
+
} catch {
|
|
354
|
+
return ''; // a layer nothing can read states no preference
|
|
355
|
+
}
|
|
356
|
+
if (typeof lean !== 'object' || lean === null || Array.isArray(lean)) return '';
|
|
357
|
+
const m = (lean as Record<string, unknown>)['mode'];
|
|
358
|
+
return typeof m === 'string' ? m.trim() : '';
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Did a human ask for this mode, and is it the one the caller is gated on?
|
|
363
|
+
*
|
|
364
|
+
* The question an installer actually has. `modeExplicit` alone is not enough —
|
|
365
|
+
* a consumer who explicitly set `eager-all` has set the key explicitly and must
|
|
366
|
+
* NOT be thinned — so the two conditions are folded here rather than left to
|
|
367
|
+
* every caller to remember to combine.
|
|
368
|
+
*/
|
|
369
|
+
export function leanProjectionModeChosen(
|
|
370
|
+
mode: LeanProjectionMode,
|
|
371
|
+
opts: ResolveOptions = {},
|
|
372
|
+
): boolean {
|
|
373
|
+
const raw = rawExplicitLeanProjectionMode(opts);
|
|
374
|
+
return raw !== '' && normalizeLeanProjectionMode(raw) === mode;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* May the INSTALLER thin this host's rule tree?
|
|
379
|
+
*
|
|
380
|
+
* The host-aware sibling of {@link leanProjectionModeChosen}, and the predicate
|
|
381
|
+
* `road-to-an-installed-layer-that-is-thinned` step 1.1 keys on. It folds the
|
|
382
|
+
* three conditions that must hold together, once, so no caller has to remember
|
|
383
|
+
* to combine them:
|
|
384
|
+
*
|
|
385
|
+
* 1. **A human asked.** `modeExplicit` — false whenever the only layer carrying
|
|
386
|
+
* the key is the shipped template, which already says `delivery`. Reading the
|
|
387
|
+
* template as consent would thin every consumer's `~/.claude/rules` as a side
|
|
388
|
+
* effect of wiring a reader, which is the owner-reserved default flip (that
|
|
389
|
+
* roadmap's blocker, decision D4).
|
|
390
|
+
* 2. **The chosen mode actually writes stubs.** A consumer who explicitly chose
|
|
391
|
+
* `eager-all` has set the key and must NOT be thinned on the strength of
|
|
392
|
+
* having an opinion.
|
|
393
|
+
* 3. **This host is in scope.** The same `hosts:` list the projector honours, so
|
|
394
|
+
* installer and projector cannot disagree about which trees are thinned.
|
|
395
|
+
*
|
|
396
|
+
* ONE `resolveLeanProjection` call, which is why this is not two
|
|
397
|
+
* {@link leanProjectionModeChosen} calls: that one answers "is the chosen mode
|
|
398
|
+
* exactly X" and knows nothing about `hosts`, so a caller combining it with a
|
|
399
|
+
* host check by hand would re-create the fold this function exists to own.
|
|
400
|
+
*
|
|
401
|
+
* That is one CALL and two cascade READS here, because reading `modeExplicit`
|
|
402
|
+
* triggers its lazy getter and a second, template-isolated load. The installer
|
|
403
|
+
* runs once per deploy and does not care; the cost is named rather than rounded
|
|
404
|
+
* down because the same resolver serves the per-prompt delivery concern, which
|
|
405
|
+
* does NOT read provenance and therefore does not pay it.
|
|
406
|
+
*/
|
|
407
|
+
export function installerThinsHost(hostId: string, opts: ResolveOptions = {}): boolean {
|
|
408
|
+
const { mode, hosts, modeExplicit } = resolveLeanProjection({
|
|
409
|
+
...opts,
|
|
410
|
+
settingsPath: opts.settingsPath ?? NO_PROJECT_LAYER,
|
|
411
|
+
});
|
|
412
|
+
return modeExplicit && thinsHost(mode, hosts.hosts, hostId);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* A path no tree contains, so the PROJECT cascade contributes nothing.
|
|
417
|
+
*
|
|
418
|
+
* The same device {@link NO_TEMPLATE_LAYER} uses, pointed at the other end of
|
|
419
|
+
* the cascade, and the reason is scope rather than isolation: the thing
|
|
420
|
+
* {@link installerThinsHost} gates is a mutation of `~/.claude/rules`, which
|
|
421
|
+
* belongs to the MACHINE. A per-checkout value must not decide it, in either
|
|
422
|
+
* direction — a project saying `delivery` would thin the layer every other
|
|
423
|
+
* project on that machine reads, and a project saying `eager-all` would
|
|
424
|
+
* suppress an opt-in the user wrote user-globally, because the project cascade
|
|
425
|
+
* merges last and wins.
|
|
426
|
+
*
|
|
427
|
+
* `load_agent_settings` reads `user_global_settings_paths()` regardless of what
|
|
428
|
+
* `project_path` it is given, so pointing the project layer at nothing leaves
|
|
429
|
+
* exactly the machine-global layers — which is the scope the installer's
|
|
430
|
+
* sibling `_resolve_global_rule_scope` already resolves for the same deploy.
|
|
431
|
+
* A caller may still pass an explicit `settingsPath` (tests pin one). A
|
|
432
|
+
* `projectRoot` handed to {@link installerThinsHost} is DISCARDED — the `??`
|
|
433
|
+
* chain terminates at `settingsPath` before `projectRoot` is consulted — which
|
|
434
|
+
* is the intended behaviour and is stated here because a caller passing it and
|
|
435
|
+
* expecting it honoured would otherwise get no signal.
|
|
436
|
+
*/
|
|
437
|
+
const NO_PROJECT_LAYER = path.join(
|
|
438
|
+
path.sep,
|
|
439
|
+
'dev',
|
|
440
|
+
'null',
|
|
441
|
+
'agent-config-absent-project-settings.yml',
|
|
442
|
+
);
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
import { load_anthropic_key } from '../ai_council/clients.js';
|
|
40
|
+
import { sanitize_text } from './retrieval_sanitize.js';
|
|
40
41
|
import type {
|
|
41
42
|
GenerationRequest,
|
|
42
43
|
GenerationResult,
|
|
@@ -140,10 +141,19 @@ export function anthropicGenerator(keyPath: string | null = null): TextGenerator
|
|
|
140
141
|
);
|
|
141
142
|
}
|
|
142
143
|
const data = (await resp.json()) as AnthropicResponse;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
// Sanitize AT THE TRANSPORT, which is the choke point and one call site.
|
|
145
|
+
// A flag every caller has to remember is the instruction-only
|
|
146
|
+
// enforcement this package diagnoses in itself, and a partially
|
|
147
|
+
// sanitized world — some callers filtered, some not — is worse than
|
|
148
|
+
// either end state. The floor is a no-op on ordinary text, so what
|
|
149
|
+
// changes here is only a response that carries a hidden-instruction
|
|
150
|
+
// vector; see `docs/contracts/retrieval-read-surfaces.md`.
|
|
151
|
+
const text = sanitize_text(
|
|
152
|
+
(data.content ?? [])
|
|
153
|
+
.filter((b) => b.type === 'text')
|
|
154
|
+
.map((b) => b.text ?? '')
|
|
155
|
+
.join(''),
|
|
156
|
+
);
|
|
147
157
|
// An empty body is returned AS an empty body rather than repaired here.
|
|
148
158
|
// The arm's own output contract refuses it and classifies the refusal;
|
|
149
159
|
// repairing it in the transport would move a decision into the layer
|
|
@@ -12,9 +12,11 @@
|
|
|
12
12
|
* a property of the `user_prompt_submit` SLOT, not of any one concern: the host
|
|
13
13
|
* delivers a background task notification on the same slot as a typed prompt,
|
|
14
14
|
* so every concern that consumes or replaces per-turn state has the same defect.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Three are known — the git-authorization ledger with its pending-refusal
|
|
16
|
+
* record, the suggestion-capture latch, and `language_mirror_hook`'s reply
|
|
17
|
+
* pin, which does not consult this predicate at all and so pins a language
|
|
18
|
+
* from a frame nobody typed. A predicate private to one of them would have
|
|
19
|
+
* repaired one and left the others, which is risk 4 of
|
|
18
20
|
* `road-to-turn-bound-authorization-integrity`.
|
|
19
21
|
*
|
|
20
22
|
* **The discriminator, quoted from a captured payload rather than from
|
|
@@ -26,6 +28,16 @@
|
|
|
26
28
|
* `<task-id>`, `<tool-use-id>`, `<status>` and `<summary>` children. A typed
|
|
27
29
|
* turn carries none of them.
|
|
28
30
|
*
|
|
31
|
+
* **The third shape, added 2026-10-03, found the same way.** A subagent
|
|
32
|
+
* hand-back arrives on this slot as `<agent-message from="…">`, and 12 of the
|
|
33
|
+
* 153 hook-sourced user records in the capture open with it — every one on
|
|
34
|
+
* `hook:claude:UserPromptSubmit`. It was found because one landed 13 seconds
|
|
35
|
+
* after a merge and rewrote the git-authorization ledger to
|
|
36
|
+
* `prompt_chars: 5599`, the length of the injected frame rather than of any
|
|
37
|
+
* sentence a human sent. Its prefix stops before the `>` because the element
|
|
38
|
+
* carries an attribute; that is a shorter literal than the other two, not a
|
|
39
|
+
* substring match — it is still anchored at position zero.
|
|
40
|
+
*
|
|
29
41
|
* **Prefix, not substring, and that is the whole care in this file.** A
|
|
30
42
|
* notification is a synthetic turn the host constructs, so the element opens it.
|
|
31
43
|
* Matching anywhere in the text would make the question "why did this
|
|
@@ -37,6 +49,7 @@
|
|
|
37
49
|
export const MACHINE_WAKE_PREFIXES: readonly string[] = [
|
|
38
50
|
'<task-notification>',
|
|
39
51
|
'<system-reminder>',
|
|
52
|
+
'<agent-message',
|
|
40
53
|
];
|
|
41
54
|
|
|
42
55
|
/** @see MACHINE_WAKE_PREFIXES — unknown shapes answer `true`, deliberately. */
|