@event4u/agent-config 16.1.0 → 16.2.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 +237 -248
- package/dist/agent-src/commands/roadmap/process-full.md +1 -1
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- 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/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +16 -1
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +23 -0
- 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 +260 -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/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-delegate/{chunk-S3VFXMTM.js → chunk-4XFP2Y3E.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-7XGBX6ZH.js} +471 -387
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-FP36SWJD.js} +432 -144
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-IGD6ERX6.js} +31 -0
- package/dist/cli-delegate/{chunk-FXYUYU4N.js → chunk-JNMVLWLR.js} +42 -1
- package/dist/cli-delegate/{chunk-QJWAUMJW.js → chunk-YJ72UIAK.js} +730 -15
- package/dist/cli-delegate/cmd_conformance.js +902 -782
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_export.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +4 -4
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_prune.js +2 -2
- package/dist/cli-delegate/cmd_route_audit.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +2 -2
- package/dist/cli-delegate/cmd_uninstall.js +2 -2
- package/dist/cli-delegate/cmd_validate.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +10 -10
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +6666 -2581
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/install.mjs +848 -733
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +2747 -1510
- package/dist/server/schemas/settings.js +23 -0
- 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 +6 -4
- package/package.json +4 -4
- 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 +260 -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/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 +29 -0
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +2 -2
- package/src/config/gate-coverage.yml +234 -3
- package/src/config/gate-violation-baselines.json +7 -3
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +2 -2
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +18 -4
- package/src/scripts/_cli/cmd_doctor.ts +5 -19
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/turn_end_refusals.ts +525 -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/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/before_complete_hook.ts +340 -23
- package/src/scripts/bench_hook_latency.ts +412 -5
- 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 +245 -3
- package/src/scripts/check_finding_dispositions.ts +22 -3
- package/src/scripts/check_generator_sync.ts +71 -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 +47 -5
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/compile_hook_manifest.ts +60 -16
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +42 -5
- package/src/scripts/hooks/block_config_weakening.ts +229 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +314 -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 +1 -2
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- 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 +25 -19
- 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 +128 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +128 -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 +25 -4
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- 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 +8 -5
- 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 +49 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +1 -2
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +337 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/install.ts +3 -4
- 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 +55 -0
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_skill_ranker_baseline.ts +305 -51
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_standing_payload_by_host.ts +1 -1
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +4 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +359 -10
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/trigger_eval_grandfather.json +0 -2
- 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 +31 -0
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
- /package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-7RQP4UDH.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"fingerprint":"95034cc0:97356","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","tools":["AskUserQuestion","AskQuestion","UserQuestion","ask_user_question","ask_question","user_question"],"needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"chain-nudge":{"script":"src/scripts/hooks/chain_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"code-graph-context":{"script":"src/scripts/hooks/code_graph_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"obligation-settle":{"script":"src/scripts/hooks/obligation_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"review-baseline":{"script":"src/scripts/hooks/review_baseline_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"memory-recall":{"script":"src/scripts/hooks/memory_recall_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Bash","Edit","Write","MultiEdit","str-replace-editor","save-file","launch-process"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","review-baseline","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","memory-recall"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"ask":"native","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","review-baseline","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","verify-before-complete","team-review-gate","end-review-nudge","obligation-settle","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","one-question-per-ask","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","memory-recall"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","memory-recall"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"ask":"text","fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
|
|
1
|
+
{"fingerprint":"92eb4d7160f46e49f0924f0a3a86ef88434b528fa14506ef19242c8527d80580:99792","manifest":{"schema_version":1,"concerns":{"chat-history":{"script":"src/scripts/chat_history.ts","args":["hook-dispatch"],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["result"]},"hot-context":{"script":"src/scripts/hot_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"handoff-context":{"script":"src/scripts/handoff_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"roadmap-progress":{"script":"src/scripts/roadmap_progress_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"onboarding-gate":{"script":"src/scripts/onboarding_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"context-hygiene":{"script":"src/scripts/context_hygiene_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"verify-before-complete":{"script":"src/scripts/before_complete_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"ship-diff-volume":{"script":"src/scripts/hooks/ship_diff_volume_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"minimal-safe-diff":{"script":"src/scripts/minimal_safe_diff_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"injection-scan":{"script":"src/scripts/injection_scan_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"block-no-verify":{"script":"src/scripts/hooks/block_no_verify.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-kernel-rule-writes":{"script":"src/scripts/hooks/block_kernel_rule_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"block-plumbing-writes":{"script":"src/scripts/hooks/block_plumbing_writes.ts","args":[],"fail_closed":true,"severity":"blocking","needs_payload_bodies":["input"]},"one-question-per-ask":{"script":"src/scripts/hooks/one_question_per_ask_hook.ts","args":[],"fail_closed":false,"severity":"blocking","tools":["AskUserQuestion","AskQuestion","UserQuestion","ask_user_question","ask_question","user_question"],"needs_payload_bodies":["input"]},"block-speaking-inbox-dir":{"script":"src/scripts/hooks/block_speaking_inbox_dir.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"block-config-weakening":{"script":"src/scripts/hooks/block_config_weakening.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"rtk-wrap":{"script":"src/scripts/hooks/rtk_wrap_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-slop":{"script":"src/scripts/hooks/design_slop_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass":{"script":"src/scripts/hooks/design_pass_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"design-pass-stop":{"script":"src/scripts/hooks/design_pass_hook.ts","args":["--slot","stop"],"fail_closed":false,"severity":"advisory"},"ui-route-nudge":{"script":"src/scripts/hooks/ui_route_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"suggestion-capture":{"script":"src/scripts/hooks/suggestion_capture_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"chain-nudge":{"script":"src/scripts/hooks/chain_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"code-graph-context":{"script":"src/scripts/hooks/code_graph_context_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Grep","Glob","Read"],"needs_payload_bodies":["input"]},"memory-learn":{"script":"src/scripts/memory_learn_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"first-run-gate":{"script":"src/scripts/first_run_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"profile-staleness":{"script":"src/scripts/profile_staleness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"wrapper-freshness":{"script":"src/scripts/wrapper_freshness_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"surface-probe":{"script":"src/scripts/surface_probe_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"team-review-gate":{"script":"src/scripts/team_review_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"pr-url-reminder":{"script":"src/scripts/pr_url_reminder_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"push-settle":{"script":"src/scripts/hooks/push_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input","result"]},"language-mirror":{"script":"src/scripts/language_mirror_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"git-authorization":{"script":"src/scripts/git_authorization_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"evidence-independence":{"script":"src/scripts/hooks/evidence_independence.ts","args":[],"fail_closed":false,"severity":"blocking","needs_payload_bodies":["input"]},"session-canary":{"script":"src/scripts/session_canary_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"council-availability":{"script":"src/scripts/council_availability_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-disclosure":{"script":"src/scripts/telemetry_disclosure_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"telemetry-flush":{"script":"src/scripts/hooks/telemetry_flush_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"self-repair":{"script":"src/scripts/self_repair_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"session-register":{"script":"src/scripts/session_register_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"orchestration-record":{"script":"src/scripts/hooks/orchestration_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"],"needs_payload_bodies":["input","result"]},"telemetry-usage":{"script":"src/scripts/hooks/telemetry_usage_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Skill"],"needs_payload_bodies":["input"]},"delegation-nudge":{"script":"src/scripts/hooks/delegation_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":1},"skill-route":{"script":"src/scripts/hooks/skill_route_hook.ts","args":[],"fail_closed":false,"severity":"advisory","nudge_rank":2},"rule-inject":{"script":"src/scripts/hooks/rule_inject_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"obligation-settle":{"script":"src/scripts/hooks/obligation_settle_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"end-review-nudge":{"script":"src/scripts/hooks/end_review_nudge_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"review-baseline":{"script":"src/scripts/hooks/review_baseline_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"turn-end-gate":{"script":"src/scripts/hooks/turn_end_gate_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"comment-discipline":{"script":"src/scripts/hooks/comment_discipline_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write","Edit"],"needs_payload_bodies":["input"]},"edit-shape":{"script":"src/scripts/hooks/edit_shape_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Write"],"needs_payload_bodies":["input"]},"reread-guard":{"script":"src/scripts/hooks/reread_guard_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Read","Edit","Write"],"needs_payload_bodies":["input"]},"memory-recall":{"script":"src/scripts/hooks/memory_recall_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Bash","Edit","Write","MultiEdit","str-replace-editor","save-file","launch-process"],"needs_payload_bodies":["input"]},"session-eol":{"script":"src/scripts/hooks/session_eol_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"run-continuation":{"script":"src/scripts/hooks/run_continuation_hook.ts","args":[],"fail_closed":false,"severity":"blocking"},"interruption-ledger":{"script":"src/scripts/hooks/interruption_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory","skip_on_refusal_retry":true},"subagent-ledger":{"script":"src/scripts/hooks/subagent_ledger_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"tool-result-bytes":{"script":"src/scripts/hooks/tool_result_bytes_hook.ts","args":[],"fail_closed":false,"severity":"advisory"},"spawn-guard-shadow":{"script":"src/scripts/hooks/spawn_guard_shadow_hook.ts","args":[],"fail_closed":false,"severity":"advisory","tools":["Agent","Task"]},"source-first-gate":{"script":"src/scripts/hooks/source_first_gate_hook.ts","args":[],"fail_closed":false,"severity":"advisory","needs_payload_bodies":["input"]},"journal-record":{"script":"src/scripts/hooks/journal_record_hook.ts","args":[],"fail_closed":false,"severity":"advisory"}},"roles":{"worker":{"drop":["delegation-nudge","skill-route","end-review-nudge","review-baseline","council-availability","team-review-gate","self-repair","session-eol","interruption-ledger"]}},"platforms":{"augment":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","memory-recall"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"claude":{"ask":"native","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register","review-baseline","journal-record"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush","journal-record"],"stop":["chat-history","verify-before-complete","team-review-gate","end-review-nudge","obligation-settle","turn-end-gate","self-repair","session-register","session-eol","interruption-ledger","roadmap-progress","design-pass-stop","suggestion-capture","journal-record","run-continuation"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","delegation-nudge","skill-route","git-authorization","session-canary","self-repair","session-register","rule-inject","suggestion-capture","journal-record"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","one-question-per-ask","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","memory-recall"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","language-mirror","design-pass","journal-record"],"pre_compact":["language-mirror","rule-inject","journal-record"],"subagent_start":["subagent-ledger","journal-record"],"subagent_stop":["subagent-ledger","journal-record"]},"cowork":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"pre_tool_use":["block-no-verify","evidence-independence","block-kernel-rule-writes","block-plumbing-writes","block-config-weakening","block-speaking-inbox-dir","rtk-wrap","design-slop","ui-route-nudge","code-graph-context","chain-nudge","ship-diff-volume","reread-guard","spawn-guard-shadow","source-first-gate","memory-recall"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"],"subagent_start":["subagent-ledger"],"subagent_stop":["subagent-ledger"]},"cursor":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"cline":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"windsurf":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","profile-staleness","wrapper-freshness","surface-probe","session-register"],"stop":["chat-history","verify-before-complete","self-repair","session-register","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","language-mirror","git-authorization","session-canary","self-repair","session-register"]},"gemini":{"ask":"text","session_start":["chat-history","hot-context","handoff-context","session-canary","council-availability","telemetry-disclosure","first-run-gate","onboarding-gate","verify-before-complete","minimal-safe-diff","profile-staleness","wrapper-freshness","surface-probe","session-register"],"session_end":["chat-history","memory-learn","session-register","roadmap-progress","telemetry-flush"],"stop":["chat-history","verify-before-complete","self-repair","session-register","roadmap-progress","design-pass-stop"],"user_prompt_submit":["chat-history","verify-before-complete","minimal-safe-diff","language-mirror","git-authorization","session-canary","self-repair","session-register"],"post_tool_use":["chat-history","roadmap-progress","context-hygiene","verify-before-complete","minimal-safe-diff","injection-scan","pr-url-reminder","push-settle","orchestration-record","telemetry-usage","tool-result-bytes","edit-shape","comment-discipline","design-pass"]},"copilot":{"ask":"text","fallback_only":true}},"native_event_aliases":{"augment":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use"},"claude":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cowork":{"SessionStart":"session_start","SessionEnd":"session_end","Stop":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact","SubagentStart":"subagent_start","SubagentStop":"subagent_stop"},"cursor":{"sessionStart":"session_start","sessionEnd":"session_end","stop":"stop","beforeSubmitPrompt":"user_prompt_submit","postToolUse":"post_tool_use","preToolUse":"pre_tool_use","preCompact":"pre_compact"},"cline":{"TaskStart":"session_start","TaskResume":"session_start","TaskComplete":"session_end","TaskCancel":"stop","UserPromptSubmit":"user_prompt_submit","PostToolUse":"post_tool_use","PreToolUse":"pre_tool_use","PreCompact":"pre_compact"},"windsurf":{"pre_user_prompt":"user_prompt_submit","post_cascade_response":"stop","post_setup_worktree":"session_start"},"gemini":{"SessionStart":"session_start","SessionEnd":"session_end","BeforeAgent":"user_prompt_submit","AfterAgent":"stop","BeforeTool":"pre_tool_use","AfterTool":"post_tool_use"}}}}
|
|
@@ -150,6 +150,21 @@ concerns:
|
|
|
150
150
|
# Warn-in-context (exit 2), never blocks. Default-OFF: no-ops unless
|
|
151
151
|
# hooks.injection_scan.enabled is true in .agent-settings.yml. The runtime
|
|
152
152
|
# backstop layered on the always-on untrusted-input-defense rule.
|
|
153
|
+
#
|
|
154
|
+
# THE INPUT IT READS, AND WHY IT CANNOT MOVE TO A BLOCKING SLOT
|
|
155
|
+
# (road-to-a-content-scanner-on-a-slot-that-can-refuse 1.1). It scans the
|
|
156
|
+
# tool RESULT -- fetched pages, file reads, MCP/tool responses -- which is
|
|
157
|
+
# why it declares `result` below. `pre_tool_use` is the only slot on this
|
|
158
|
+
# host with a non-null `block_exit`, and a pre-call payload has no tool
|
|
159
|
+
# response in it: the `result` body class resolves to `tool_response` /
|
|
160
|
+
# `toolResponse` / `tool_result` / `toolUseResult` (hooks/payload_stub.ts),
|
|
161
|
+
# none of which exist before the call runs. So rebinding for the deny would
|
|
162
|
+
# leave the scanner reading the arguments it was never written to inspect --
|
|
163
|
+
# more enforcing-looking and strictly less detecting. It stays on
|
|
164
|
+
# `post_tool_use` and the published claims say `detected, not blocked`;
|
|
165
|
+
# `docs/enforcement-by-host.md` § "The slot rows are not a statement about
|
|
166
|
+
# any concern" carries the reasoning, and `check_enforcement_matrix` prints
|
|
167
|
+
# the per-host binding audit that keeps it from drifting back.
|
|
153
168
|
injection-scan:
|
|
154
169
|
script: src/scripts/injection_scan_hook.ts
|
|
155
170
|
args: []
|
|
@@ -186,6 +201,27 @@ concerns:
|
|
|
186
201
|
fail_closed: true
|
|
187
202
|
severity: blocking
|
|
188
203
|
needs_payload_bodies: [input]
|
|
204
|
+
# road-to-a-kernel-that-guards-its-plumbing 1.2 — the build-output half of
|
|
205
|
+
# "one mechanism per file class". PreToolUse guard: DENIES Write/Edit/
|
|
206
|
+
# NotebookEdit and the shell write shapes whose target is
|
|
207
|
+
# `dist/hooks/dispatch.js` (the esbuild bundle) or `hooks/hooks.json` (the
|
|
208
|
+
# host binding file). Both are GENERATED — by `npm run build:hooks` and by
|
|
209
|
+
# condense.ts via `task sync` — so a hand edit is never legitimate, and a
|
|
210
|
+
# hand-edited bundle reaches every dispatch while being invisible in a source
|
|
211
|
+
# review. The plumbing SOURCES beside them (hook_manifest.yaml,
|
|
212
|
+
# host_lowering.yaml, the *-dispatcher.sh trampolines, both budget files) are
|
|
213
|
+
# edited on purpose all the time and carry the ADR-268 § 4 ratification
|
|
214
|
+
# RECORD instead — check_kernel_edit_ratified, path set extended by step 1.1.
|
|
215
|
+
# The legitimate builds pass: they reach these files through a build tool,
|
|
216
|
+
# not through a redirect / in-place sed / tee / mv shape. fail_closed: true —
|
|
217
|
+
# the guarantee is about a DETECTED write; a malformed envelope with no
|
|
218
|
+
# target allows. No agent-accessible override; the fix is to rebuild.
|
|
219
|
+
block-plumbing-writes:
|
|
220
|
+
script: src/scripts/hooks/block_plumbing_writes.ts
|
|
221
|
+
args: []
|
|
222
|
+
fail_closed: true
|
|
223
|
+
severity: blocking
|
|
224
|
+
needs_payload_bodies: [input]
|
|
189
225
|
# road-to-asked-not-parked Phase 5.1 — one question per structured-ask call.
|
|
190
226
|
# PreToolUse guard: DENIES a call to a host's native question picker whose
|
|
191
227
|
# payload carries more than one question. `ask-when-uncertain`'s Iron Law is
|
|
@@ -462,8 +498,9 @@ concerns:
|
|
|
462
498
|
# `name === 'Grep' || name === 'Glob'` and `name === 'Read'`
|
|
463
499
|
# (code_graph_context_hook.ts), and a test pins the manifest list against it.
|
|
464
500
|
#
|
|
465
|
-
# Deliberately NOT declared on the
|
|
466
|
-
# (block-no-verify, block-kernel-rule-writes, block-
|
|
501
|
+
# Deliberately NOT declared on the four blocking PreToolUse guards
|
|
502
|
+
# (block-no-verify, block-kernel-rule-writes, block-plumbing-writes,
|
|
503
|
+
# block-config-weakening): their
|
|
467
504
|
# tool sets span host-specific naming variants (`Bash` / `BashTool` /
|
|
468
505
|
# `launch-process` / `launch_process`, `str-replace-editor` /
|
|
469
506
|
# `str_replace_editor` / `save-file` / …), so a list that misses one variant
|
|
@@ -1387,7 +1424,7 @@ platforms:
|
|
|
1387
1424
|
session_start: [chat-history, hot-context, handoff-context, session-canary, council-availability, telemetry-disclosure, first-run-gate, onboarding-gate, verify-before-complete, minimal-safe-diff, profile-staleness, wrapper-freshness, surface-probe, session-register]
|
|
1388
1425
|
session_end: [chat-history, memory-learn, session-register, roadmap-progress, telemetry-flush]
|
|
1389
1426
|
stop: [chat-history, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1390
|
-
pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-context, chain-nudge, ship-diff-volume, reread-guard, memory-recall]
|
|
1427
|
+
pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-plumbing-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-context, chain-nudge, ship-diff-volume, reread-guard, memory-recall]
|
|
1391
1428
|
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, push-settle, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1392
1429
|
|
|
1393
1430
|
claude:
|
|
@@ -1419,7 +1456,7 @@ platforms:
|
|
|
1419
1456
|
# (+16,329 GPT tok, +69 % on the thin rule layer) are in
|
|
1420
1457
|
# `project_thin_rules.path_only_ids`; the receiver is
|
|
1421
1458
|
# `agents/roadmaps/stubs/road-to-a-path-route-under-delivery.md`.
|
|
1422
|
-
pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, one-question-per-ask, rtk-wrap, design-slop, ui-route-nudge, code-graph-context, chain-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, memory-recall]
|
|
1459
|
+
pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-plumbing-writes, block-config-weakening, block-speaking-inbox-dir, one-question-per-ask, rtk-wrap, design-slop, ui-route-nudge, code-graph-context, chain-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, memory-recall]
|
|
1423
1460
|
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, push-settle, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, language-mirror, design-pass, journal-record]
|
|
1424
1461
|
# `language-mirror` — round-5 § 6.1. `pre_compact` sets a pin-lost marker;
|
|
1425
1462
|
# the `post_tool_use` entry above re-emits the pin exactly once while that
|
|
@@ -1466,7 +1503,7 @@ platforms:
|
|
|
1466
1503
|
# still costs the dispatch, and its entire output is thrown away.
|
|
1467
1504
|
stop: [chat-history, verify-before-complete, self-repair, session-register, roadmap-progress, design-pass-stop]
|
|
1468
1505
|
user_prompt_submit: [chat-history, verify-before-complete, minimal-safe-diff, language-mirror, git-authorization, session-canary, self-repair, session-register]
|
|
1469
|
-
pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-context, chain-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, memory-recall]
|
|
1506
|
+
pre_tool_use: [block-no-verify, evidence-independence, block-kernel-rule-writes, block-plumbing-writes, block-config-weakening, block-speaking-inbox-dir, rtk-wrap, design-slop, ui-route-nudge, code-graph-context, chain-nudge, ship-diff-volume, reread-guard, spawn-guard-shadow, source-first-gate, memory-recall]
|
|
1470
1507
|
post_tool_use: [chat-history, roadmap-progress, context-hygiene, verify-before-complete, minimal-safe-diff, injection-scan, pr-url-reminder, push-settle, orchestration-record, telemetry-usage, tool-result-bytes, edit-shape, comment-discipline, design-pass]
|
|
1471
1508
|
# subagent-ledger IS bound here, unlike the two nudges above, and the
|
|
1472
1509
|
# difference is the delivery channel rather than the platform: the nudges
|
|
@@ -45,14 +45,45 @@ 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
|
+
import * as yaml from 'js-yaml';
|
|
49
|
+
|
|
50
|
+
import {
|
|
51
|
+
buildSettingsClassIndex,
|
|
52
|
+
classOfPath,
|
|
53
|
+
parseSettingsClassRows,
|
|
54
|
+
type SettingsClass,
|
|
55
|
+
} from '../../shared/settingsClasses.js';
|
|
48
56
|
import { EDIT_TOOLS } from '../minimal_safe_diff_hook.js';
|
|
49
57
|
import { readHookStdin } from './hook_stdin.js';
|
|
58
|
+
import { EXIT_ALLOW, EXIT_BLOCK, EXIT_WARN } from './exit_codes.js';
|
|
50
59
|
|
|
51
60
|
const _HERE = fileURLToPath(import.meta.url);
|
|
52
61
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
/**
|
|
63
|
+
* This package's own root — where the shipped class contract lives.
|
|
64
|
+
*
|
|
65
|
+
* RESOLVED BY SEARCH, not by counting `..` segments. This file runs from three
|
|
66
|
+
* layouts: the source tree, an installed `node_modules/@event4u/agent-config/`,
|
|
67
|
+
* and inlined into `dist/hooks/dispatch.js`, where every module shares the
|
|
68
|
+
* BUNDLE's `import.meta.url` and a fixed hop count lands somewhere else
|
|
69
|
+
* entirely. A review flagged the fixed-hop version as resolving a different
|
|
70
|
+
* root from the one the package occupies; walking up to the nearest directory
|
|
71
|
+
* that actually carries the contract answers the question the guard is asking
|
|
72
|
+
* ("where is the contract") instead of a proxy for it.
|
|
73
|
+
*
|
|
74
|
+
* `null` when no ancestor carries it — which is the fail-closed input to
|
|
75
|
+
* `readClassIndex`, not a silent default root.
|
|
76
|
+
*/
|
|
77
|
+
export function findPackageRoot(from: string): string | null {
|
|
78
|
+
let dir = path.dirname(from);
|
|
79
|
+
for (let i = 0; i < 12; i++) {
|
|
80
|
+
if (fs.existsSync(path.join(dir, SETTINGS_CLASSES_RELATIVE))) return dir;
|
|
81
|
+
const up = path.dirname(dir);
|
|
82
|
+
if (up === dir) break;
|
|
83
|
+
dir = up;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
56
87
|
|
|
57
88
|
/**
|
|
58
89
|
* The stated cap from `autonomous-execution` § Antipattern. Crossing it in one
|
|
@@ -81,7 +112,18 @@ const _PATH_KEYS: readonly string[] = ['file_path', 'path', 'target_file', 'file
|
|
|
81
112
|
* where "weakening" needs context a tool call does not carry (a baseline count
|
|
82
113
|
* may legitimately reset after a refactor); those warn and never block.
|
|
83
114
|
*/
|
|
84
|
-
export type ConfigKind = 'allowlist' | 'advisory' | null;
|
|
115
|
+
export type ConfigKind = 'allowlist' | 'advisory' | 'class-c' | null;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Project settings files whose keys this guard fences. User-global files are
|
|
119
|
+
* never in reach — the hook only sees a path a tool call named, and the writes
|
|
120
|
+
* that reach `~/.event4u/` go through `settings:set`, which applies its own
|
|
121
|
+
* per-key refusal.
|
|
122
|
+
*/
|
|
123
|
+
const CLASS_C_BASENAMES: readonly string[] = ['.agent-settings.yml', '.agent-settings.yaml', 'settings.json'];
|
|
124
|
+
|
|
125
|
+
/** Where the class contract lives, relative to the package root. */
|
|
126
|
+
export const SETTINGS_CLASSES_RELATIVE = 'docs/contracts/settings-classes.md';
|
|
85
127
|
|
|
86
128
|
/** Classify a target path into a config surface, or null for everything else. */
|
|
87
129
|
export function classify_target(p: string): ConfigKind {
|
|
@@ -96,9 +138,100 @@ export function classify_target(p: string): ConfigKind {
|
|
|
96
138
|
if (/-budget(s)?\.(json|ya?ml)$/.test(base) || base === 'budgets.yml') {
|
|
97
139
|
return 'advisory';
|
|
98
140
|
}
|
|
141
|
+
// `settings.json` only under a host directory: the bare name is common
|
|
142
|
+
// enough elsewhere that classifying it on the basename alone would fence
|
|
143
|
+
// files that carry no settings key at all.
|
|
144
|
+
if (base === 'settings.json') {
|
|
145
|
+
return /(^|\/)\.(claude|cursor|augment|windsurf)\/settings\.json$/.test(posix) ? 'class-c' : null;
|
|
146
|
+
}
|
|
147
|
+
if (CLASS_C_BASENAMES.includes(base)) {
|
|
148
|
+
return 'class-c';
|
|
149
|
+
}
|
|
99
150
|
return null;
|
|
100
151
|
}
|
|
101
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Leaf key paths of a parsed settings document, dotted.
|
|
155
|
+
*
|
|
156
|
+
* LEAVES ONLY, and the choice is load-bearing in both directions. A class-C key
|
|
157
|
+
* whose value is a MAP (`hooks`, say) has children that never appear as their
|
|
158
|
+
* own rows in the contract, so emitting only leaves and letting `classOfPath`
|
|
159
|
+
* walk up to the nearest classified ancestor is what makes `hooks.enabled`
|
|
160
|
+
* resolve to C. Emitting the interior nodes as well would double-count the same
|
|
161
|
+
* change and report a parent that nothing edited.
|
|
162
|
+
*/
|
|
163
|
+
export function leafPaths(value: unknown, prefix = ''): Map<string, string> {
|
|
164
|
+
const out = new Map<string, string>();
|
|
165
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
166
|
+
if (prefix !== '') out.set(prefix, JSON.stringify(value ?? null));
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
|
|
170
|
+
const key = prefix === '' ? k : `${prefix}.${k}`;
|
|
171
|
+
for (const [ck, cv] of leafPaths(v, key)) out.set(ck, cv);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Parse a settings document, or `null` when it is not parseable.
|
|
178
|
+
*
|
|
179
|
+
* `null` is NOT "no keys changed" — the caller treats it as an unreadable
|
|
180
|
+
* corpus and refuses, because a guard that allows whatever it cannot parse is
|
|
181
|
+
* bypassed by making the file unparseable for one call.
|
|
182
|
+
*/
|
|
183
|
+
export function parseSettingsDoc(text: string, rel: string): unknown | null {
|
|
184
|
+
try {
|
|
185
|
+
return rel.endsWith('.json') ? (JSON.parse(text) as unknown) : yaml.load(text);
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Dotted paths whose value differs between two settings documents. */
|
|
192
|
+
export function changedKeys(before: unknown, after: unknown): string[] {
|
|
193
|
+
const a = leafPaths(before);
|
|
194
|
+
const b = leafPaths(after);
|
|
195
|
+
const out = new Set<string>();
|
|
196
|
+
for (const [k, v] of b) if (a.get(k) !== v) out.add(k);
|
|
197
|
+
for (const k of a.keys()) if (!b.has(k)) out.add(k);
|
|
198
|
+
return [...out].sort();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The class index, read from the shipped contract. `null` when it cannot be
|
|
203
|
+
* read AT ALL, which the caller treats as fail-closed.
|
|
204
|
+
*
|
|
205
|
+
* Not cached: the file is small, and a cache would keep a stale fence alive
|
|
206
|
+
* across an upgrade that reclassified a key — the same reasoning the server's
|
|
207
|
+
* own reader states for the same file.
|
|
208
|
+
*/
|
|
209
|
+
export function readClassIndex(packageRoot: string): Map<string, SettingsClass> | null {
|
|
210
|
+
try {
|
|
211
|
+
const text = fs.readFileSync(path.join(packageRoot, SETTINGS_CLASSES_RELATIVE), 'utf-8');
|
|
212
|
+
const index = buildSettingsClassIndex(parseSettingsClassRows(text));
|
|
213
|
+
return index.size === 0 ? null : index;
|
|
214
|
+
} catch {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The guarded subset of a change list.
|
|
221
|
+
*
|
|
222
|
+
* A key is guarded when its nearest classified ancestor is C, and ALSO when
|
|
223
|
+
* nothing on its path is classified at all — the same per-key refusal
|
|
224
|
+
* `settings:set` and the GUI write route already apply, reached here through
|
|
225
|
+
* the same shared classifier rather than a second copy of the rule.
|
|
226
|
+
*/
|
|
227
|
+
export function guardedKeys(index: ReadonlyMap<string, SettingsClass> | null, keys: readonly string[]): string[] {
|
|
228
|
+
if (index === null) return [...keys];
|
|
229
|
+
return keys.filter((k) => {
|
|
230
|
+
const cls = classOfPath(index, k);
|
|
231
|
+
return cls === 'C' || cls === undefined;
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
102
235
|
/**
|
|
103
236
|
* Count allowlist entries in a blob.
|
|
104
237
|
*
|
|
@@ -167,6 +300,89 @@ export interface Decision {
|
|
|
167
300
|
}
|
|
168
301
|
|
|
169
302
|
/** Decide from the cumulative session total for one allowlist file. */
|
|
303
|
+
/**
|
|
304
|
+
* The refusal reason for a class-C settings edit, or `null` to allow.
|
|
305
|
+
*
|
|
306
|
+
* WHAT THIS FENCES, and what it deliberately does not. The unit is the KEY, not
|
|
307
|
+
* the file: a Class A key stays agent-writable through this path exactly as it
|
|
308
|
+
* is through `settings:set`, and fencing the whole file would make an ordinary
|
|
309
|
+
* preference edit need a human. Only a key the contract classifies C — or one
|
|
310
|
+
* nothing on its path classifies at all, which is the same fail-closed default
|
|
311
|
+
* the CLI writer applies — is refused.
|
|
312
|
+
*
|
|
313
|
+
* THE UNPARSEABLE CASES REFUSE, both of them, and for the same reason. A
|
|
314
|
+
* contract this guard cannot read leaves it with no way to tell a C key from an
|
|
315
|
+
* A key; a resulting document it cannot parse leaves it with no key list at
|
|
316
|
+
* all. Allowing either would mean the fence is lifted by making one file
|
|
317
|
+
* unreadable for the length of one tool call, which is a bypass with no
|
|
318
|
+
* authorisation step in it.
|
|
319
|
+
*
|
|
320
|
+
* WHAT IT CANNOT SEE: an edit applied through a shell redirect rather than an
|
|
321
|
+
* edit tool — `EDIT_TOOLS` is the corpus, and the shell shapes are
|
|
322
|
+
* `block_plumbing_writes`' subject, not this one.
|
|
323
|
+
*/
|
|
324
|
+
export function classCVerdict(
|
|
325
|
+
ti: JsonObject,
|
|
326
|
+
on_disk: string | null,
|
|
327
|
+
rel_path: string,
|
|
328
|
+
index: ReadonlyMap<string, SettingsClass> | null,
|
|
329
|
+
): string | null {
|
|
330
|
+
const before = on_disk === null ? null : parseSettingsDoc(on_disk, rel_path);
|
|
331
|
+
|
|
332
|
+
const content = ti['content'];
|
|
333
|
+
const oldStr = ti['old_string'];
|
|
334
|
+
const newStr = ti['new_string'];
|
|
335
|
+
let afterText: string | null = null;
|
|
336
|
+
if (typeof content === 'string') {
|
|
337
|
+
afterText = content;
|
|
338
|
+
} else if (typeof oldStr === 'string' && typeof newStr === 'string' && on_disk !== null) {
|
|
339
|
+
if (!on_disk.includes(oldStr)) return null; // the edit will not apply
|
|
340
|
+
// `replace_all` is the host's own flag and it changes WHICH text the
|
|
341
|
+
// edit produces. Modelling only the first occurrence let a
|
|
342
|
+
// `replace_all` edit whose SECOND occurrence is the Class C one pass
|
|
343
|
+
// this guard while the real edit changed it — the guard evaluating a
|
|
344
|
+
// different edit from the one executed. Reported by an independent
|
|
345
|
+
// review before this landed.
|
|
346
|
+
const all = ti['replace_all'];
|
|
347
|
+
if (all !== undefined && typeof all !== 'boolean') {
|
|
348
|
+
return (
|
|
349
|
+
`${rel_path}: this edit carries a \`replace_all\` value the guard cannot ` +
|
|
350
|
+
'interpret, so the text it would produce is unknown and no key can be ' +
|
|
351
|
+
'cleared. Re-send it as a plain edit, or write the change through ' +
|
|
352
|
+
'`agent-config settings:set`.'
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
afterText = all === true ? on_disk.split(oldStr).join(newStr) : on_disk.replace(oldStr, newStr);
|
|
356
|
+
}
|
|
357
|
+
if (afterText === null) return null;
|
|
358
|
+
|
|
359
|
+
const after = parseSettingsDoc(afterText, rel_path);
|
|
360
|
+
if (after === null) {
|
|
361
|
+
return (
|
|
362
|
+
`${rel_path}: the result of this edit does not parse as settings, so no key ` +
|
|
363
|
+
'list can be derived and no key can be cleared. Fix the syntax, or write the ' +
|
|
364
|
+
'change through `agent-config settings:set`, which refuses a Class C key by name.'
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const guarded = guardedKeys(index, changedKeys(before, after));
|
|
369
|
+
if (guarded.length === 0) return null;
|
|
370
|
+
|
|
371
|
+
const unreadable =
|
|
372
|
+
index === null
|
|
373
|
+
? ' The class contract could not be read, so EVERY changed key is treated as ' +
|
|
374
|
+
'guarded — that is the fail-closed direction, not a classification.'
|
|
375
|
+
: '';
|
|
376
|
+
return (
|
|
377
|
+
`${rel_path}: this edit changes ${String(guarded.length)} guarded settings key(s) — ` +
|
|
378
|
+
`${guarded.slice(0, 5).join(', ')}${guarded.length > 5 ? ', …' : ''}.` +
|
|
379
|
+
unreadable +
|
|
380
|
+
' A Class C key is a policy dial (spend ceiling, allowlist, gate switch, hooks) and ' +
|
|
381
|
+
'is a human edit by contract: docs/contracts/settings-classes.md. Every other key in ' +
|
|
382
|
+
'this file stays writable.'
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
|
|
170
386
|
export function decide(kind: ConfigKind, rel_path: string, session_total: number, added: number): Decision {
|
|
171
387
|
if (kind === null || added <= 0) {
|
|
172
388
|
return { action: 'allow', reason: '' };
|
|
@@ -292,6 +508,15 @@ export function main(): number {
|
|
|
292
508
|
} catch {
|
|
293
509
|
on_disk = null;
|
|
294
510
|
}
|
|
511
|
+
if (kind === 'class-c') {
|
|
512
|
+
const rel_c = path.relative(root, abs) || p;
|
|
513
|
+
const pkg = findPackageRoot(_HERE);
|
|
514
|
+
const verdict = classCVerdict(ti, on_disk, rel_c, pkg === null ? null : readClassIndex(pkg));
|
|
515
|
+
if (verdict === null) continue;
|
|
516
|
+
process.stderr.write(`block-config-weakening: BLOCKED — ${verdict}\n`);
|
|
517
|
+
return EXIT_BLOCK;
|
|
518
|
+
}
|
|
519
|
+
|
|
295
520
|
const added = added_entries(ti, on_disk);
|
|
296
521
|
if (added <= 0) {
|
|
297
522
|
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
|
/**
|