@event4u/agent-config 16.0.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 +289 -140
- package/CONTRIBUTING.md +9 -0
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +26 -0
- package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
- package/dist/agent-src/commands/challenge-me/closure.md +178 -0
- package/dist/agent-src/commands/challenge-me.md +9 -2
- package/dist/agent-src/commands/council/default.md +25 -5
- package/dist/agent-src/commands/feature/plan.md +28 -1
- package/dist/agent-src/commands/feature/roadmap.md +28 -1
- package/dist/agent-src/commands/implement-ticket.md +27 -0
- package/dist/agent-src/commands/jira-ticket.md +27 -0
- package/dist/agent-src/commands/pr/create.md +29 -0
- package/dist/agent-src/commands/pr/merge.md +60 -9
- package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
- package/dist/agent-src/commands/roadmap/create.md +74 -27
- package/dist/agent-src/commands/roadmap/materialize.md +27 -0
- package/dist/agent-src/commands/roadmap/process-full.md +123 -18
- package/dist/agent-src/commands/team.md +22 -0
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +47 -0
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +19 -23
- package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
- package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
- package/dist/agent-src/rules/autonomous-execution.md +15 -8
- package/dist/agent-src/rules/delegation-policy.md +23 -45
- package/dist/agent-src/rules/design-fidelity.md +32 -37
- package/dist/agent-src/rules/evaluator-independence.md +43 -49
- package/dist/agent-src/rules/test-first.md +41 -0
- 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 +3 -3
- package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
- package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
- package/dist/agent-src/skills/database/data/manifest.json +4 -4
- package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
- package/dist/agent-src/skills/design-review/SKILL.md +80 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +30 -5
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
- 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/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
- package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
- package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +23 -0
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +218 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -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/check_update_banner.js +40 -2
- package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-4XFP2Y3E.js} +1 -1
- package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
- package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
- package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
- package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-7XGBX6ZH.js} +973 -555
- package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
- package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-FP36SWJD.js} +587 -141
- package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-IGD6ERX6.js} +62 -7
- package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-JNMVLWLR.js} +99 -14
- package/dist/cli-delegate/{chunk-H32DGUJH.js → chunk-P6ZHP5W2.js} +1 -1
- package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
- package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
- package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
- package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
- package/dist/cli-delegate/{chunk-QJWAUMJW.js → chunk-YJ72UIAK.js} +730 -15
- 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 +985 -831
- package/dist/cli-delegate/cmd_doctor.js +7 -5
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +9 -7
- package/dist/cli-delegate/cmd_fleet.js +4 -2
- package/dist/cli-delegate/cmd_handoff.js +7 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +4 -2
- package/dist/cli-delegate/cmd_prune.js +10 -8
- package/dist/cli-delegate/cmd_route_audit.js +3 -3
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +4 -4
- package/dist/cli-delegate/cmd_settings_get.js +28 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +10 -8
- package/dist/cli-delegate/cmd_uninstall.js +16 -13
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +12 -10
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +90 -43
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +10 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +8 -6
- package/dist/hooks/dispatch.js +7682 -2772
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudeRuleRewrite.js +14 -3
- package/dist/install/conflict.js +60 -10
- package/dist/install/conflictTracker.js +218 -0
- package/dist/install/fsPrimitives.js +54 -0
- package/dist/install/install.mjs +2200 -1559
- package/dist/install/manifestFiles.js +259 -0
- package/dist/install/preflight.js +14 -2
- package/dist/install/preserve.js +157 -0
- package/dist/install/recordedOwnership.js +132 -0
- package/dist/install/txlog.js +11 -2
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +3066 -1470
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +3 -2
- package/dist/scripts/_lib/fs_atomic.js +167 -0
- package/dist/scripts/_lib/installed_tools.js +460 -0
- package/dist/scripts/_lib/lean_projection_mode.js +3 -2
- package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
- package/dist/server/routes/install.js +8 -0
- package/dist/server/routes/wizard.js +9 -3
- package/dist/server/schemas/settings.js +40 -5
- package/dist/shared/missionExecution.js +97 -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/MIGRATION.md +103 -0
- package/docs/contracts/settings-classes.md +28 -7
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
- package/docs/guidelines/design-fidelity-routing.md +29 -0
- package/package.json +4 -4
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
- 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 +168 -27
- package/src/config/auto-rule-budget.json +16 -0
- package/src/config/ci-local-parity.yml +36 -5
- package/src/config/continuity-surface.json +23 -2
- package/src/config/gate-coverage.yml +377 -13
- package/src/config/gate-violation-baselines.json +10 -6
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +4 -2
- package/src/config/loop-surfaces.yaml +215 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/platform-anchor.json +3 -2
- package/src/config/release-gate-locality.yml +11 -0
- package/src/config/routing-coverage-seed.json +33 -5
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/install/claudeRuleRewrite.ts +16 -2
- package/src/install/conflict.ts +65 -9
- package/src/install/conflictTracker.ts +299 -0
- package/src/install/fsPrimitives.ts +54 -0
- package/src/install/manifestFiles.ts +312 -0
- package/src/install/preflight.ts +16 -2
- package/src/install/preserve.ts +205 -0
- package/src/install/recordedOwnership.ts +149 -0
- package/src/install/txlog.ts +11 -2
- package/src/install/types.ts +19 -4
- package/src/scripts/_cli/cmd_conformance.ts +88 -15
- package/src/scripts/_cli/cmd_doctor.ts +7 -20
- package/src/scripts/_cli/cmd_route_explain.ts +9 -2
- package/src/scripts/_cli/cmd_settings_get.ts +44 -0
- package/src/scripts/_cli/doctor_execution.ts +173 -0
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_lib/activation_payload.ts +247 -0
- package/src/scripts/_lib/agent_settings.ts +4 -2
- package/src/scripts/_lib/authority_path.ts +102 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cascade_base.ts +94 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/changelog_eras.ts +7 -2
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/continuation_ladder.ts +149 -2
- package/src/scripts/_lib/council_transport.ts +129 -0
- package/src/scripts/_lib/delivery_ready.ts +112 -0
- package/src/scripts/_lib/forge_protection.ts +381 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/hook_platform_keys.ts +27 -0
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/json_python_parity.ts +127 -0
- package/src/scripts/_lib/lean_projection_mode.ts +14 -3
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/loop_surfaces.ts +382 -0
- package/src/scripts/_lib/mission_record.ts +190 -0
- package/src/scripts/_lib/obligation_frequency.ts +217 -0
- package/src/scripts/_lib/obligations.ts +513 -0
- package/src/scripts/_lib/orchestration_record.ts +11 -20
- 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 +201 -11
- package/src/scripts/_lib/release_holds.ts +493 -0
- package/src/scripts/_lib/release_migration_gate.ts +184 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/rides_along.ts +102 -0
- package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/test_delta.ts +166 -0
- package/src/scripts/_lib/test_provenance.ts +171 -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/typed_op_grant.ts +246 -0
- package/src/scripts/_lib/typed_op_watch.ts +185 -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_council/config.ts +8 -11
- package/src/scripts/ai_council/fallback_config.ts +5 -3
- package/src/scripts/ai_council/ownership_classes.ts +118 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/ask_block_census.ts +285 -15
- 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 +866 -0
- package/src/scripts/check_finding_dispositions.ts +22 -3
- package/src/scripts/check_gate_reachability.ts +173 -10
- package/src/scripts/check_generator_sync.ts +1025 -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_preamble_payload_budget.ts +75 -2
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +33 -1
- package/src/scripts/check_release_holds.ts +568 -0
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_rule_projection_integrity.ts +22 -12
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_test_delta.ts +294 -0
- package/src/scripts/check_test_weakening.ts +299 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +447 -0
- package/src/scripts/compile_hook_manifest.ts +102 -18
- package/src/scripts/council_record_shape.ts +209 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +127 -11
- 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 +6 -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 +221 -5
- 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 +97 -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 +539 -0
- package/src/scripts/hooks/obligation_settle_hook.ts +328 -0
- 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 +55 -4
- package/src/scripts/hooks/run_continuation_hook.ts +30 -35
- 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/hooks_doctor.ts +85 -0
- package/src/scripts/hooks_status.ts +19 -0
- package/src/scripts/install.ts +109 -210
- package/src/scripts/janitor.ts +7 -0
- package/src/scripts/lint_decision_classes.ts +464 -0
- 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 +66 -0
- package/src/scripts/lint_major_migration_sections.ts +450 -0
- package/src/scripts/lint_plan_risk_register.ts +47 -3
- package/src/scripts/lint_roadmap_blockers.ts +139 -12
- package/src/scripts/lint_roadmap_producers.ts +202 -0
- 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_rule_budget.ts +101 -5
- 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/new_roadmap.ts +37 -0
- package/src/scripts/orchestration_record.ts +0 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/release.ts +14 -98
- package/src/scripts/release_drill.ts +267 -1
- package/src/scripts/release_publication.ts +64 -1
- package/src/scripts/report_enforcement_drift.ts +566 -0
- package/src/scripts/report_host_injection_effect.ts +3 -11
- 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 +26 -152
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/command.schema.json +48 -0
- package/src/scripts/schemas/review-findings.schema.json +4 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/scope_growth.ts +219 -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 -3
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +774 -0
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +62 -7
- package/src/shared/missionExecution.ts +126 -0
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
- package/dist/ui/assets/index-D0jaCRPM.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
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
*
|
|
44
44
|
* Exit codes: 0 allow · 2 block (stderr carries the reason).
|
|
45
45
|
*/
|
|
46
|
+
import { spawnSync } from "node:child_process";
|
|
46
47
|
import crypto from "node:crypto";
|
|
47
48
|
import fs from "node:fs";
|
|
48
49
|
import path from "node:path";
|
|
@@ -50,8 +51,9 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
50
51
|
|
|
51
52
|
import { atomic_write_json } from "./state_io.js";
|
|
52
53
|
import { readHookStdin } from "./hook_stdin.js";
|
|
54
|
+
import { isCodePath, isTestPath } from "../_lib/test_delta.js";
|
|
55
|
+
import { EXIT_ALLOW, EXIT_BLOCK } from './exit_codes.js';
|
|
53
56
|
|
|
54
|
-
const EXIT_ALLOW = 0;
|
|
55
57
|
// MUST equal dispatch_hook.EXIT_BLOCK. The dispatcher's internal ladder is
|
|
56
58
|
// 0 allow / 1 block / 2 warn — NOT the 2-means-block shape a PreToolUse guard
|
|
57
59
|
// reads naturally from Claude's own native contract. This constant was 2 when
|
|
@@ -59,7 +61,6 @@ const EXIT_ALLOW = 0;
|
|
|
59
61
|
// and the gate emitted advisory context while the operation went through.
|
|
60
62
|
// Pinned against the dispatcher's export by
|
|
61
63
|
// tests/hooks/concern_block_exit_parity.test.ts.
|
|
62
|
-
const EXIT_BLOCK = 1;
|
|
63
64
|
|
|
64
65
|
export const STATE_FILE = path.join("agents", "state", "evidence-dispatch.json");
|
|
65
66
|
|
|
@@ -324,6 +325,79 @@ export function decide(
|
|
|
324
325
|
};
|
|
325
326
|
}
|
|
326
327
|
|
|
328
|
+
/**
|
|
329
|
+
* The one-commit test-authorship flag —
|
|
330
|
+
* `road-to-adversarial-verification-and-long-runs` 2.4, third clause.
|
|
331
|
+
*
|
|
332
|
+
* A commit staging BOTH a test and code it could cover is the shape of L0 on the
|
|
333
|
+
* independence scale — the implementer wrote the evaluator — and it is the one
|
|
334
|
+
* case nobody sees, because the diff looks exactly like a well-tested change.
|
|
335
|
+
*
|
|
336
|
+
* **It reads the STAGED SET and the command, and nothing else.** It does NOT
|
|
337
|
+
* read a session id, an author or a timestamp, so it cannot distinguish an
|
|
338
|
+
* implementer who wrote both from one committing a test another session authored
|
|
339
|
+
* — an independent review of this function caught an earlier docstring here
|
|
340
|
+
* claiming a session boundary the code never reads, which is exactly the
|
|
341
|
+
* over-claim `evaluator-independence` exists over. The honest reading is: this
|
|
342
|
+
* is the shape L0 takes in a diff, surfaced so the level is stated rather than
|
|
343
|
+
* inferred.
|
|
344
|
+
*
|
|
345
|
+
* **WARN, never block.** L0 is explicitly permitted as a fallback, so refusing it
|
|
346
|
+
* would forbid a legal state; and a signal this coarse may surface, never refuse.
|
|
347
|
+
*
|
|
348
|
+
* Returns `null` when nothing is worth saying — i.e. this is not a commit.
|
|
349
|
+
*/
|
|
350
|
+
export function sameSessionTestFlag(command: string | null): string | null {
|
|
351
|
+
if (command === null || !/\bgit\b[^|;&]*\bcommit\b/.test(command)) return null;
|
|
352
|
+
return SAME_SESSION_TEXT;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const SAME_SESSION_TEXT =
|
|
356
|
+
"This commit stages both a test and code it could cover — the shape L0 takes " +
|
|
357
|
+
"in a diff, where the implementer authored the evaluator. This check reads the " +
|
|
358
|
+
"staged set only: it cannot tell who wrote the test, so it is a prompt to STATE " +
|
|
359
|
+
"the level, not a finding that you are at L0. L0 is a permitted FALLBACK, not " +
|
|
360
|
+
"the default: where a second session, a second model or a second provider was " +
|
|
361
|
+
"available, the test should have come from one of them. Say which in the commit " +
|
|
362
|
+
"or the PR body — a diff looks identical either way. See evaluator-independence " +
|
|
363
|
+
"§ Tests are evaluators.";
|
|
364
|
+
|
|
365
|
+
/** Both a test path and a production path in one changed set. */
|
|
366
|
+
export function touchesTestAndCode(paths: readonly string[]): boolean {
|
|
367
|
+
return paths.some(isTestPath) && paths.some(isCodePath);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** The shell command this envelope is about, across the key names hosts use. */
|
|
371
|
+
function _commandOf(envelope: JsonObject): string | null {
|
|
372
|
+
const payload = _isObject(envelope["payload"]) ? envelope["payload"] : envelope;
|
|
373
|
+
const input = _isObject(payload["tool_input"]) ? payload["tool_input"] : payload;
|
|
374
|
+
for (const key of ["command", "cmd", "shell_command"]) {
|
|
375
|
+
const v = input[key];
|
|
376
|
+
if (typeof v === "string" && v !== "") return v;
|
|
377
|
+
}
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Staged paths, or `null` when git cannot answer.
|
|
383
|
+
*
|
|
384
|
+
* `null` is not "nothing staged" — it is "no reading", and the caller must not
|
|
385
|
+
* turn an unreadable index into a silent clean bill. A hook that cannot measure
|
|
386
|
+
* says nothing rather than implying a measurement.
|
|
387
|
+
*/
|
|
388
|
+
function _stagedPaths(consumer_root: string): string[] | null {
|
|
389
|
+
const r = spawnSync("git", ["diff", "--cached", "--name-only"], {
|
|
390
|
+
cwd: consumer_root,
|
|
391
|
+
encoding: "utf8",
|
|
392
|
+
});
|
|
393
|
+
if (r.status !== 0) return null;
|
|
394
|
+
const out = r.stdout
|
|
395
|
+
.split("\n")
|
|
396
|
+
.map((s) => s.trim())
|
|
397
|
+
.filter((s) => s !== "");
|
|
398
|
+
return out.length === 0 ? null : out;
|
|
399
|
+
}
|
|
400
|
+
|
|
327
401
|
export function run(stdin_text: string, options: { consumer_root: string }): number {
|
|
328
402
|
let envelope: JsonObject = {};
|
|
329
403
|
if (stdin_text.trim()) {
|
|
@@ -355,6 +429,27 @@ export function run(stdin_text: string, options: { consumer_root: string }): num
|
|
|
355
429
|
}
|
|
356
430
|
|
|
357
431
|
const [tool, prompt] = extractDispatch(envelope);
|
|
432
|
+
|
|
433
|
+
// 2.4 — the one-commit test-authorship flag, checked BEFORE the dispatch
|
|
434
|
+
// branch and returning early. A commit envelope carries no evaluation prompt,
|
|
435
|
+
// so `decide` would classify it as not-an-evaluation and allow it silently;
|
|
436
|
+
// running both would mean the commit path fell through to a counter that is
|
|
437
|
+
// about evaluation dispatches and would be wrong to advance here.
|
|
438
|
+
//
|
|
439
|
+
// CHEAP TEST FIRST, and that ordering is the finding rather than a style
|
|
440
|
+
// preference: `_stagedPaths` spawns `git diff --cached`, and this concern is
|
|
441
|
+
// bound on `pre_tool_use`, so reading the index before the regex made every
|
|
442
|
+
// Read, Edit, Grep and Task dispatch in every session pay a subprocess. The
|
|
443
|
+
// regex answers "is this even a commit" for free.
|
|
444
|
+
const flag = sameSessionTestFlag(_commandOf(envelope));
|
|
445
|
+
if (flag !== null) {
|
|
446
|
+
const staged = _stagedPaths(options.consumer_root);
|
|
447
|
+
if (staged !== null && touchesTestAndCode(staged)) {
|
|
448
|
+
process.stdout.write(`${JSON.stringify({ decision: "warn", reason: flag })}\n`);
|
|
449
|
+
return EXIT_ALLOW;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
358
453
|
const decision = decide(tool, prompt, state.evaluations.length);
|
|
359
454
|
|
|
360
455
|
if (decision.evaluations > state.evaluations.length) {
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hook exit-code table — one frozen definition, imported everywhere.
|
|
3
|
+
*
|
|
4
|
+
* road-to-a-kernel-that-guards-its-plumbing 4.1.
|
|
5
|
+
*
|
|
6
|
+
* WHAT WAS WRONG. Thirty-three files under `src/scripts/hooks/` each declared
|
|
7
|
+
* their own `const EXIT_ALLOW = 0` / `EXIT_BLOCK = 1` / `EXIT_WARN = 2`, two of
|
|
8
|
+
* them under a third name (`EXIT_OK`). Thirty-three copies of a contract is
|
|
9
|
+
* thirty-three places it can be changed in one and not the others, and the
|
|
10
|
+
* change that matters here is not a typo: exit 1 and exit 2 mean the OPPOSITE
|
|
11
|
+
* things on Claude Code from what they mean in this tree's internal language
|
|
12
|
+
* (`host_semantics.ts` exists entirely to lower one onto the other). A number
|
|
13
|
+
* that means "advisory" here and "hard deny" there is not a constant anyone
|
|
14
|
+
* should be re-deriving per file.
|
|
15
|
+
*
|
|
16
|
+
* WHAT THE TABLE ADDS BEYOND THE NUMBERS. `owner` and `authorizedBy` — who
|
|
17
|
+
* decides that a concern emits this code, and what authorises the dispatcher to
|
|
18
|
+
* act on it. A bare `1` in a concern says nothing about whether that concern was
|
|
19
|
+
* ever allowed to refuse; the manifest's `severity` is what authorises it, and
|
|
20
|
+
* the dispatcher enforces that ceiling (`_is_advisory`). Recording it beside the
|
|
21
|
+
* number is what makes the table a contract rather than an enum.
|
|
22
|
+
*
|
|
23
|
+
* WHAT IS NOT IN SCOPE. The `*-dispatcher.sh` trampolines carry inline
|
|
24
|
+
* `process.exit(0)` in a `node -e` one-liner that reads a workspace root off
|
|
25
|
+
* stdin. They are shell, they cannot import, and their exit code is the
|
|
26
|
+
* one-liner's, never a verdict. `lint_exit_codes` scans `.ts` only.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Allow — the concern has no objection. The overwhelmingly common verdict. */
|
|
30
|
+
export const EXIT_ALLOW = 0;
|
|
31
|
+
|
|
32
|
+
/** Block — the concern refuses. Only a `severity: blocking` concern may. */
|
|
33
|
+
export const EXIT_BLOCK = 1;
|
|
34
|
+
|
|
35
|
+
/** Warn — advisory. The dispatcher exits 0 and surfaces the reason. */
|
|
36
|
+
export const EXIT_WARN = 2;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Error — the concern crashed or could not decide.
|
|
40
|
+
*
|
|
41
|
+
* `3` is the floor, not the only value: the dispatcher treats every rc ≥ 3 the
|
|
42
|
+
* same way, and what that way IS depends on the concern's declared severity.
|
|
43
|
+
*/
|
|
44
|
+
export const EXIT_ERROR = 3;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Usage error on the process's OWN argv — not a verdict, and not a row.
|
|
48
|
+
*
|
|
49
|
+
* `dispatch_hook` and `replay_hook` are also CLIs: run with `--platform`
|
|
50
|
+
* missing they exit before any concern is consulted. The number is 2 by the
|
|
51
|
+
* POSIX convention for a usage error, which COLLIDES with `EXIT_WARN` by
|
|
52
|
+
* coincidence and not by meaning — nothing advisory has happened, and no
|
|
53
|
+
* concern has spoken.
|
|
54
|
+
*
|
|
55
|
+
* Named rather than left as a bare `2`, and kept OUT of `EXIT_CODES`, because
|
|
56
|
+
* both readings are wrong: importing `EXIT_WARN` here would assert a verdict
|
|
57
|
+
* that was never reached, and adding a fifth row would put a non-verdict in a
|
|
58
|
+
* table whose whole subject is what a concern may say. `lint_exit_codes`
|
|
59
|
+
* refuses the bare literal, so the next writer has to pick one of the two
|
|
60
|
+
* deliberately.
|
|
61
|
+
*/
|
|
62
|
+
export const EXIT_USAGE = 2;
|
|
63
|
+
|
|
64
|
+
export interface ExitCodeRow {
|
|
65
|
+
/** The numeric code, or its floor for the open-ended error band. */
|
|
66
|
+
readonly code: number;
|
|
67
|
+
readonly name: 'allow' | 'block' | 'warn' | 'error';
|
|
68
|
+
readonly meaning: string;
|
|
69
|
+
/** Who decides a concern emits this code. */
|
|
70
|
+
readonly owner: string;
|
|
71
|
+
/** What authorises the dispatcher to act on it. */
|
|
72
|
+
readonly authorizedBy: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* The frozen table. Ordered by code; the last row is a band, not a value.
|
|
77
|
+
*
|
|
78
|
+
* `as const` plus `Object.freeze` rather than a plain array: this is the kind of
|
|
79
|
+
* structure a later convenience ("just push a row for the new verdict") turns
|
|
80
|
+
* into a fourth dialect, and the whole point of the file is that there is one.
|
|
81
|
+
*/
|
|
82
|
+
export const EXIT_CODES: readonly ExitCodeRow[] = Object.freeze([
|
|
83
|
+
Object.freeze({
|
|
84
|
+
code: EXIT_ALLOW,
|
|
85
|
+
name: 'allow',
|
|
86
|
+
meaning: 'no objection; the dispatcher passes the call through',
|
|
87
|
+
owner: 'every concern — the default verdict',
|
|
88
|
+
authorizedBy: 'nothing; allowing needs no authority',
|
|
89
|
+
}),
|
|
90
|
+
Object.freeze({
|
|
91
|
+
code: EXIT_BLOCK,
|
|
92
|
+
name: 'block',
|
|
93
|
+
meaning: 'refuse the call; the dispatcher lowers this onto the host deny channel',
|
|
94
|
+
owner: 'a concern declared `severity: blocking` in hook_manifest.yaml',
|
|
95
|
+
authorizedBy:
|
|
96
|
+
'the manifest entry plus its row in the BLOCKING_ALLOWLIST of ' +
|
|
97
|
+
'tests/hooks/concern_severity.test.ts — an advisory concern emitting this is ' +
|
|
98
|
+
'downgraded to warn by dispatch_hook._is_advisory',
|
|
99
|
+
}),
|
|
100
|
+
Object.freeze({
|
|
101
|
+
code: EXIT_WARN,
|
|
102
|
+
name: 'warn',
|
|
103
|
+
meaning: 'advisory; the dispatcher exits 0 and surfaces the reason',
|
|
104
|
+
owner: 'any concern',
|
|
105
|
+
authorizedBy:
|
|
106
|
+
'nothing; warning is the ceiling for an advisory concern and is always available ' +
|
|
107
|
+
'to a blocking one',
|
|
108
|
+
}),
|
|
109
|
+
Object.freeze({
|
|
110
|
+
code: EXIT_ERROR,
|
|
111
|
+
name: 'error',
|
|
112
|
+
meaning:
|
|
113
|
+
'the concern crashed, timed out, or could not decide — any rc >= 3. The dispatcher ' +
|
|
114
|
+
'resolves it by the concern`s declared severity, never by the number itself',
|
|
115
|
+
owner: 'no concern emits this on purpose; the runtime does',
|
|
116
|
+
authorizedBy:
|
|
117
|
+
'hook_manifest.yaml `fail_closed` and `severity` together — see ' +
|
|
118
|
+
'docs/contracts/hook-architecture-v1.md § Exit-code semantics',
|
|
119
|
+
}),
|
|
120
|
+
] as const);
|
|
121
|
+
|
|
122
|
+
/** The row a raw exit code resolves to, or `null` for a negative code. */
|
|
123
|
+
export function rowFor(code: number): ExitCodeRow | null {
|
|
124
|
+
if (code >= EXIT_ERROR) {
|
|
125
|
+
return EXIT_CODES[3] ?? null;
|
|
126
|
+
}
|
|
127
|
+
return EXIT_CODES.find((r) => r.code === code) ?? null;
|
|
128
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fingerprint":"08575a71d81fd8a5ef9e4b400f4a38cb66c26e1dd701d98f3cdc0bdc9e4758b4:22235","table":{"schema_version":1,"hosts":{"claude":{"surfaces":{"any":{"entry_shape":"claude-settings-hooks","json_shape":"hook-specific-output","fail_policy":"propagate","timeout_unit":"seconds","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://code.claude.com/docs/en/hooks.md","docs_digest":"9dd68316c1111c118e3ddb82861ac6271a8cd164cee0d371b26165efff35fe88","probe_at":"2026-09-06","host_version":"2.1.263","expires":"2027-09-06"},"slots":{"session_start":{"native":"SessionStart","block_exit":null,"answered_at":"2026-09-29"},"session_end":{"native":"SessionEnd","block_exit":null,"answered_at":"2026-09-29"},"stop":{"native":"Stop","block_exit":2,"answered_at":"2026-09-29"},"user_prompt_submit":{"native":"UserPromptSubmit","block_exit":2,"answered_at":"2026-09-29"},"pre_tool_use":{"native":"PreToolUse","block_exit":2,"answered_at":"2026-09-29"},"post_tool_use":{"native":"PostToolUse","block_exit":null,"answered_at":"2026-09-29"},"pre_compact":{"native":"PreCompact","block_exit":null,"answered_at":"2026-09-29"},"subagent_start":{"native":"SubagentStart","block_exit":null,"answered_at":"2026-09-29"},"subagent_stop":{"native":"SubagentStop","block_exit":null,"answered_at":"2026-09-29"}}}}},"augment":{"surfaces":{"any":{"entry_shape":"augment-settings-hooks","json_shape":"none","fail_policy":"discard","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://docs.augmentcode.com/cli/hooks.md","docs_digest":"e500823be8303717020c1823f670e06d100108f6e3ac4b8d12a46d91fd1898fa","probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{"session_start":{"native":"SessionStart","block_exit":null,"answered_at":"2026-09-29"},"session_end":{"native":"SessionEnd","block_exit":null,"answered_at":"2026-09-29"},"stop":{"native":"Stop","block_exit":null,"answered_at":"2026-09-29"},"pre_tool_use":{"native":"PreToolUse","block_exit":null,"answered_at":"2026-09-29"},"post_tool_use":{"native":"PostToolUse","block_exit":null,"answered_at":"2026-09-29"}}}}},"cursor":{"surfaces":{"any":{"entry_shape":"cursor-hooks-json","json_shape":"none","fail_policy":"propagate","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://cursor.com/docs/hooks.md","docs_digest":"7294a2d63b19d79a5283c948afe174cba8b06a7585563d34a2c41b90f5df0d39","probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{"session_start":{"native":"sessionStart","block_exit":null,"answered_at":"2026-09-29"},"session_end":{"native":"sessionEnd","block_exit":null,"answered_at":"2026-09-29"},"stop":{"native":"stop","block_exit":null,"answered_at":"2026-09-29"},"user_prompt_submit":{"native":"beforeSubmitPrompt","block_exit":null,"answered_at":"2026-09-29"},"post_tool_use":{"native":"postToolUse","block_exit":null,"answered_at":"2026-09-29"}}}}},"cline":{"surfaces":{"any":{"entry_shape":"cline-per-event-script","json_shape":"none","fail_policy":"discard","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://docs.cline.bot/customization/hooks.md","docs_digest":"ef87561721f4cb80fe6d682b6866d638a4952dd416d36cd5ab398426ce64084b","probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{"session_start":{"native":["TaskStart","TaskResume"],"block_exit":null,"answered_at":"2026-09-29"},"session_end":{"native":"TaskComplete","block_exit":null,"answered_at":"2026-09-29"},"stop":{"native":"TaskCancel","block_exit":null,"answered_at":"2026-09-29"},"user_prompt_submit":{"native":"UserPromptSubmit","block_exit":null,"answered_at":"2026-09-29"},"post_tool_use":{"native":"PostToolUse","block_exit":null,"answered_at":"2026-09-29"}}}}},"windsurf":{"surfaces":{"any":{"entry_shape":"windsurf-hooks-json","json_shape":"none","fail_policy":"propagate","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://docs.devin.ai/desktop/cascade/hooks.md","docs_digest":"460ffe7aa91998804920f6722c0153b9948eadd5edafa19582298475a19835a2","probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{"session_start":{"native":"post_setup_worktree","block_exit":null,"answered_at":"2026-09-29"},"user_prompt_submit":{"native":"pre_user_prompt","block_exit":null,"answered_at":"2026-09-29"},"stop":{"native":"post_cascade_response","block_exit":null,"answered_at":"2026-09-29"}}}}},"gemini":{"surfaces":{"any":{"entry_shape":"gemini-settings-hooks","json_shape":"none","fail_policy":"propagate","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://geminicli.com/docs/hooks/reference.md","docs_digest":"06d37f2f66812ee78bb46c37a112203376f0bae4d3b8b44ac79d0bda4b86a118","probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{"session_start":{"native":"SessionStart","block_exit":null,"answered_at":"2026-09-29","matcher":""},"session_end":{"native":"SessionEnd","block_exit":null,"answered_at":"2026-09-29","matcher":""},"stop":{"native":"AfterAgent","block_exit":null,"answered_at":"2026-09-29","matcher":""},"user_prompt_submit":{"native":"BeforeAgent","block_exit":null,"answered_at":"2026-09-29","matcher":""},"post_tool_use":{"native":"AfterTool","block_exit":null,"answered_at":"2026-09-29","matcher":".*"}}}}},"cowork":{"surfaces":{"any":{"entry_shape":"none","json_shape":"none","fail_policy":"discard","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":null,"docs_digest":null,"probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{}}}},"copilot":{"surfaces":{"any":{"entry_shape":"none","json_shape":"none","fail_policy":"discard","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://docs.github.com/en/copilot/concepts/agents/hooks.md","docs_digest":"bfd40aa93ad62133efc17a50f189034f01594dc89a5d31a13a0c541d691acede","probe_at":null,"host_version":null,"expires":"2027-09-29"},"slots":{}}}},"codex":{"surfaces":{"any":{"entry_shape":"none","json_shape":"none","fail_policy":"discard","timeout_unit":"unknown","timeout_default":null,"verified":{"docs_at":"2026-09-29","docs_url":"https://developers.openai.com/codex/hooks.md","docs_digest":"724881d81f1a9fdb35ea42d4851a11b1f6606bbc6e9d2d05c1e8c466fc25c630","probe_at":"2026-10-01","host_version":"0.148.0","expires":"2027-09-29"},"slots":{}}}}}}}
|
|
@@ -21,6 +21,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
21
21
|
|
|
22
22
|
import { parse as parseYaml } from 'yaml';
|
|
23
23
|
|
|
24
|
+
import { tableFingerprint } from './table_fingerprint.js';
|
|
25
|
+
|
|
24
26
|
declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
|
|
25
27
|
const _IN_BUNDLE = typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__;
|
|
26
28
|
const _REPO_ROOT = path.resolve(
|
|
@@ -30,10 +32,59 @@ const _REPO_ROOT = path.resolve(
|
|
|
30
32
|
|
|
31
33
|
export const HOST_LOWERING_PATH = path.join(_REPO_ROOT, 'src', 'scripts', 'hooks', 'host_lowering.yaml');
|
|
32
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Compiled sibling of the table above — the same data with comments stripped.
|
|
37
|
+
*
|
|
38
|
+
* WHY IT EXISTS, measured rather than assumed. The dispatcher consults this
|
|
39
|
+
* table on EVERY dispatch (`emitFor` needs `blockExitFor`), and since
|
|
40
|
+
* `hook_manifest.json` landed it is the ONLY remaining YAML reader on that
|
|
41
|
+
* path — so it pays both its own parse and the cold load of the `yaml` module
|
|
42
|
+
* nothing else pulls in any more. Measured on one developer machine: the
|
|
43
|
+
* 16.8 kB source parses in 3.1-7.0 ms and the `yaml` module costs a further
|
|
44
|
+
* 8.1 ms to load, against `JSON.parse` of the 5.9 kB compiled form at 0.03 ms.
|
|
45
|
+
*
|
|
46
|
+
* Exactly the shape `compile_hook_manifest` already established for the
|
|
47
|
+
* manifest, including the content fingerprint — see `table_fingerprint` for
|
|
48
|
+
* why freshness is decided by content and never by mtime.
|
|
49
|
+
*/
|
|
50
|
+
export const HOST_LOWERING_JSON_PATH = path.join(_REPO_ROOT, 'src', 'scripts', 'hooks', 'host_lowering.json');
|
|
51
|
+
|
|
33
52
|
/** Provenance of a row. Every field may be null; `expires` may not. */
|
|
34
53
|
export interface VerifiedBlock {
|
|
35
54
|
docs_at: string | null;
|
|
36
55
|
docs_url: string | null;
|
|
56
|
+
/**
|
|
57
|
+
* sha256 of the `docs_url` body as last ESTABLISHED for this row.
|
|
58
|
+
*
|
|
59
|
+
* "Established" means recorded by a human-run fill, not merely seen. The
|
|
60
|
+
* watcher re-hashes the page on every run and writes the new value only
|
|
61
|
+
* when the field was empty; on a DRIFT it deliberately leaves the recorded
|
|
62
|
+
* digest alone, so the field keeps pointing at the body someone actually
|
|
63
|
+
* read while `expires` carries the alarm.
|
|
64
|
+
*
|
|
65
|
+
* Three earlier wordings were wrong and all three are named rather than
|
|
66
|
+
* quietly replaced, because each was corrected by evidence the next one
|
|
67
|
+
* then contradicted. "As fetched on `docs_at`" was refuted by the very
|
|
68
|
+
* first fill (digests taken 2026-10-01 against rows whose `docs_at` is
|
|
69
|
+
* 2026-09-29). "As fetched by the LAST digest run" was refuted by the
|
|
70
|
+
* writer (after a drift the last run computed a different hash than the
|
|
71
|
+
* field holds). "`docs_at` + `docs_digest` are ONE pair" was refuted by
|
|
72
|
+
* the same committed data as the first — stating it was a relapse, caught
|
|
73
|
+
* in review.
|
|
74
|
+
*
|
|
75
|
+
* The two fields are simply INDEPENDENT. `docs_at` dates a human reading
|
|
76
|
+
* the page for the row's ANSWERS; `docs_digest` names the body the watcher
|
|
77
|
+
* compares against. Nothing guarantees they were the same fetch, and no
|
|
78
|
+
* wording that implies they were can survive this table's own rows.
|
|
79
|
+
*
|
|
80
|
+
* Null where there is nothing to hash — a row whose `docs_url` is null —
|
|
81
|
+
* and null is also the pre-fill state `check_host_docs_digest --fetch
|
|
82
|
+
* --write` resolves. It is deliberately NOT part of the expiry test: a
|
|
83
|
+
* digest is evidence about the page, `expires` is this package's review-by
|
|
84
|
+
* date, and collapsing the two would make a vendor's CSS rebuild look like
|
|
85
|
+
* a lapsed citation.
|
|
86
|
+
*/
|
|
87
|
+
docs_digest: string | null;
|
|
37
88
|
probe_at: string | null;
|
|
38
89
|
host_version: string | null;
|
|
39
90
|
expires: string;
|
|
@@ -44,6 +95,21 @@ export interface SlotRow {
|
|
|
44
95
|
native: string[];
|
|
45
96
|
/** Exit code the host honours as a refusal here, or null if unestablished. */
|
|
46
97
|
block_exit: number | null;
|
|
98
|
+
/**
|
|
99
|
+
* The date this pair was last answered, or null when it never was.
|
|
100
|
+
*
|
|
101
|
+
* `block_exit: null` alone cannot distinguish "looked, found none" from
|
|
102
|
+
* "nobody looked", and the whole point of this table is that a zero is a
|
|
103
|
+
* fact with a date on it. `lint_hook_manifest` requires the date; the
|
|
104
|
+
* parser keeps it nullable so a malformed table still parses into
|
|
105
|
+
* something the linter can report on rather than throwing first.
|
|
106
|
+
*/
|
|
107
|
+
answered_at: string | null;
|
|
108
|
+
/**
|
|
109
|
+
* Citation for this pair, when it differs from the row's
|
|
110
|
+
* `verified.docs_url`. Absent means the row's URL is the citation.
|
|
111
|
+
*/
|
|
112
|
+
docs_url: string | null;
|
|
47
113
|
/** Entry-shape-specific extra (gemini's per-binding matcher). */
|
|
48
114
|
matcher?: string;
|
|
49
115
|
}
|
|
@@ -72,7 +138,18 @@ function _asString(v: unknown): string | null {
|
|
|
72
138
|
}
|
|
73
139
|
|
|
74
140
|
function _parse(text: string): HostLowering {
|
|
75
|
-
|
|
141
|
+
return _structure(parseYaml(text) as Record<string, unknown> | null);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Build the table from an ALREADY-PARSED document.
|
|
146
|
+
*
|
|
147
|
+
* Split out of `_parse` so the compiled-JSON fast path below reaches exactly
|
|
148
|
+
* the same validation on exactly the same shape — the YAML step is the only
|
|
149
|
+
* thing it skips. A second structuring function would be a second thing to
|
|
150
|
+
* drift; there is one, and both paths call it.
|
|
151
|
+
*/
|
|
152
|
+
function _structure(raw: Record<string, unknown> | null): HostLowering {
|
|
76
153
|
const hostsRaw = raw?.['hosts'];
|
|
77
154
|
if (typeof hostsRaw !== 'object' || hostsRaw === null) {
|
|
78
155
|
throw new Error('host_lowering.yaml: missing `hosts:` map');
|
|
@@ -96,6 +173,7 @@ function _parse(text: string): HostLowering {
|
|
|
96
173
|
verified = {
|
|
97
174
|
docs_at: _asString(verifiedRaw['docs_at']),
|
|
98
175
|
docs_url: _asString(verifiedRaw['docs_url']),
|
|
176
|
+
docs_digest: _asString(verifiedRaw['docs_digest']),
|
|
99
177
|
probe_at: _asString(verifiedRaw['probe_at']),
|
|
100
178
|
host_version: _asString(verifiedRaw['host_version']),
|
|
101
179
|
expires,
|
|
@@ -110,6 +188,8 @@ function _parse(text: string): HostLowering {
|
|
|
110
188
|
const row: SlotRow = {
|
|
111
189
|
native,
|
|
112
190
|
block_exit: typeof be === 'number' ? be : null,
|
|
191
|
+
answered_at: _asString(rv['answered_at']),
|
|
192
|
+
docs_url: _asString(rv['docs_url']),
|
|
113
193
|
};
|
|
114
194
|
if (typeof rv['matcher'] === 'string') row.matcher = rv['matcher'];
|
|
115
195
|
slots.set(slot, row);
|
|
@@ -131,12 +211,57 @@ function _parse(text: string): HostLowering {
|
|
|
131
211
|
|
|
132
212
|
let _cache: HostLowering | null = null;
|
|
133
213
|
|
|
134
|
-
/**
|
|
214
|
+
/**
|
|
215
|
+
* Parse the table once per process. Throws on a missing or malformed file.
|
|
216
|
+
*
|
|
217
|
+
* Tries the compiled sibling first and falls through to the YAML source on
|
|
218
|
+
* anything unexpected — missing, unreadable, malformed, or a fingerprint that
|
|
219
|
+
* does not match the live source. A stale or absent compiled file is therefore
|
|
220
|
+
* SLOW and never WRONG, which is the property that lets the optimisation ship
|
|
221
|
+
* without a second correctness argument.
|
|
222
|
+
*/
|
|
135
223
|
export function loadHostLowering(): HostLowering {
|
|
136
|
-
if (_cache
|
|
224
|
+
if (_cache !== null) return _cache;
|
|
225
|
+
// Reading the YAML unconditionally costs ~0.03 ms — it is the PARSE that is
|
|
226
|
+
// expensive — so the fast path still skips the whole 11-15 ms.
|
|
227
|
+
const text = fs.readFileSync(HOST_LOWERING_PATH, 'utf-8');
|
|
228
|
+
let compiled: string | null;
|
|
229
|
+
try {
|
|
230
|
+
compiled = fs.readFileSync(HOST_LOWERING_JSON_PATH, 'utf-8');
|
|
231
|
+
} catch {
|
|
232
|
+
compiled = null;
|
|
233
|
+
}
|
|
234
|
+
_cache = resolveTable(text, compiled);
|
|
137
235
|
return _cache;
|
|
138
236
|
}
|
|
139
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Pick the path and build the table — the whole decision, with no I/O.
|
|
240
|
+
*
|
|
241
|
+
* Split from `loadHostLowering` so the FALLBACK semantics are testable. They
|
|
242
|
+
* are the half that carries the risk: the fast path is easy to verify and a
|
|
243
|
+
* mis-shaped fallback would be a wrong table rather than a slow one. A test
|
|
244
|
+
* that could only reach the happy path would be watching the safe half.
|
|
245
|
+
*/
|
|
246
|
+
export function resolveTable(yamlText: string, compiledText: string | null): HostLowering {
|
|
247
|
+
if (compiledText !== null) {
|
|
248
|
+
try {
|
|
249
|
+
const raw = JSON.parse(compiledText) as Record<string, unknown>;
|
|
250
|
+
const table = raw['table'];
|
|
251
|
+
if (
|
|
252
|
+
raw['fingerprint'] === tableFingerprint(yamlText) &&
|
|
253
|
+
typeof table === 'object' &&
|
|
254
|
+
table !== null
|
|
255
|
+
) {
|
|
256
|
+
return _structure(table as Record<string, unknown>);
|
|
257
|
+
}
|
|
258
|
+
} catch {
|
|
259
|
+
// Malformed JSON → the source below. Never fail on the optimisation.
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return _parse(yamlText);
|
|
263
|
+
}
|
|
264
|
+
|
|
140
265
|
/** Test seam — drop the memoized table so a fixture can be loaded instead. */
|
|
141
266
|
export function _resetHostLoweringCache(table?: HostLowering): void {
|
|
142
267
|
_cache = table ?? null;
|