@event4u/agent-config 14.12.0 → 14.14.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 +118 -155
- package/CONTRIBUTING.md +38 -0
- package/CREDITS.md +135 -0
- package/NOTICE +13 -0
- package/README.md +8 -6
- package/dist/agent-src/commands/analyze/inbox.md +145 -2
- package/dist/agent-src/commands/feature/dev.md +7 -2
- package/dist/agent-src/commands/ghostwriter/write.md +5 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/mission/upgrade.md +1 -1
- package/dist/agent-src/commands/orchestrate.md +2 -2
- package/dist/agent-src/commands/post-as/me.md +5 -1
- package/dist/agent-src/commands/pr/merge.md +19 -6
- package/dist/agent-src/commands/roadmap/process-full.md +19 -5
- package/dist/agent-src/commands/tdd/red.md +12 -2
- package/dist/agent-src/commands/work.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
- package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
- package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -0
- package/dist/agent-src/rules/code-comment-discipline.md +6 -0
- package/dist/agent-src/rules/code-provenance.md +4 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +4 -0
- package/dist/agent-src/rules/domain-safety-retention.md +4 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
- package/dist/agent-src/rules/improve-before-implement.md +6 -8
- package/dist/agent-src/rules/laravel-routing.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +12 -34
- package/dist/agent-src/rules/symfony-routing.md +1 -1
- package/dist/agent-src/rules/token-efficiency.md +14 -0
- package/dist/agent-src/rules/tool-safety.md +4 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
- package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
- package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/dist/agent-src/scripts/stub_queue.ts +82 -0
- package/dist/agent-src/scripts/stubs_due.ts +516 -0
- package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
- package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
- package/dist/agent-src/skills/database/SKILL.md +8 -0
- package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
- package/dist/agent-src/skills/design-review/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
- package/dist/agent-src/skills/laravel/SKILL.md +35 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
- package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
- package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
- package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +97 -3
- package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
- package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/dist/cli/commands/uiAudit.js +124 -5
- package/dist/cli/registry.js +2 -0
- package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
- package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
- package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
- package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
- package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
- package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
- package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
- package/dist/cli-delegate/cmd_adr_effective.js +102 -0
- package/dist/cli-delegate/cmd_conformance.js +80 -11
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +3 -2
- package/dist/cli-delegate/cmd_fleet.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +3 -2
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +3 -2
- package/dist/cli-delegate/cmd_uninstall.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +3 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +58 -58
- 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 +2900 -1049
- package/dist/install/claudeRuleRewrite.js +254 -0
- package/dist/install/detect.js +29 -16
- package/dist/install/detect_php_shape.js +159 -0
- package/dist/install/install.mjs +634 -428
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +3 -3
- package/dist/mcp/server.mjs +4895 -2627
- package/dist/server/schemas/settings.js +3 -0
- package/dist/ui/assets/index-D0jaCRPM.js +29 -0
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/THIRD-PARTY-NOTICES.md +25 -0
- package/docs/contracts/provider-lifecycle.md +1 -1
- package/docs/contracts/settings-classes.md +10 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
- package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
- package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
- package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
- package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
- package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
- package/docs/guidelines/agent-infra/first-principles.md +2 -2
- package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
- package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
- package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
- package/docs/guidelines/agent-infra/layered-settings.md +10 -10
- package/docs/guidelines/agent-infra/memory-access.md +1 -1
- package/docs/guidelines/agent-infra/mental-models.md +3 -3
- package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
- package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
- package/docs/guidelines/agent-infra/role-contracts.md +2 -2
- package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
- package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
- package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
- package/docs/guidelines/agent-infra/six-hats.md +3 -3
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
- package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
- package/docs/guidelines/augment-portability-patterns.md +6 -4
- package/docs/guidelines/code-clarity.md +18 -0
- package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
- package/docs/guidelines/cross-role-handoff.md +2 -2
- package/docs/guidelines/design-fidelity-mechanics.md +1 -1
- package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
- package/docs/guidelines/php/database.md +90 -7
- package/docs/guidelines/prompt-templates.md +7 -7
- package/llms.txt +2 -2
- package/package.json +5 -2
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
- package/src/agent-src/scripts/guarded_baseline.ts +343 -0
- package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/src/agent-src/scripts/stub_queue.ts +82 -0
- package/src/agent-src/scripts/stubs_due.ts +516 -0
- package/src/agent-src/scripts/ticket_bundles.ts +84 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
- package/src/agent-src/templates/scripts/check_memory.ts +258 -17
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/src/config/agent-settings.template.yml +32 -3
- package/src/config/assurance-capability-registry.json +21 -9
- package/src/config/canonical-terms.yml +119 -0
- package/src/config/capability-native-outcome-bars.json +81 -0
- package/src/config/ci-local-parity.yml +80 -0
- package/src/config/drafting-channels.yml +43 -0
- package/src/config/estate-count-budget.json +57 -36
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +729 -63
- package/src/config/gate-reachability-exemptions.json +21 -0
- package/src/config/gate-violation-baselines.json +42 -19
- package/src/config/harness-evolution-budget.json +25 -0
- package/src/config/lapsed-beta-baseline.json +96 -0
- package/src/config/memory-twin-verdicts.yml +129 -0
- package/src/config/metric-registry.yml +124 -0
- package/src/config/pack-size-budget.json +16 -15
- package/src/config/preamble-payload-budget.json +12 -4
- package/src/config/profiles/balanced.ini +27 -0
- package/src/config/profiles/full.ini +27 -0
- package/src/config/profiles/minimal.ini +27 -0
- package/src/config/publish-surface.json +9 -2
- package/src/config/routing-coverage-seed.json +16 -2
- package/src/config/rule-stub-ceilings.json +133 -112
- package/src/config/turnaround-budget.json +66 -0
- package/src/install/claudeRuleRewrite.ts +288 -0
- package/src/install/detect.ts +60 -17
- package/src/install/detect_php_shape.ts +191 -0
- package/src/scripts/_cli/cmd_doctor.ts +27 -112
- package/src/scripts/_dispatch.bash +23 -0
- package/src/scripts/_lib/activation_ladder.ts +255 -0
- package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
- package/src/scripts/_lib/activation_states.ts +88 -0
- package/src/scripts/_lib/adherence_detectors.ts +143 -0
- package/src/scripts/_lib/adr_frontmatter.ts +26 -0
- package/src/scripts/_lib/arith_claims.ts +181 -0
- package/src/scripts/_lib/arm_ranking.ts +62 -0
- package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
- package/src/scripts/_lib/audit_field_provenance.ts +54 -0
- package/src/scripts/_lib/auto_dispatch.ts +32 -3
- package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
- package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
- package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
- package/src/scripts/_lib/candidate_proposer.ts +402 -0
- package/src/scripts/_lib/candidate_record.ts +601 -0
- package/src/scripts/_lib/capture_rate.ts +319 -0
- package/src/scripts/_lib/carrier_status.ts +118 -0
- package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
- package/src/scripts/_lib/collector_denominator.ts +771 -0
- package/src/scripts/_lib/collector_record.ts +340 -0
- package/src/scripts/_lib/collector_store.ts +664 -0
- package/src/scripts/_lib/collector_supervision.ts +827 -0
- package/src/scripts/_lib/concern_estate.ts +77 -0
- package/src/scripts/_lib/config_chain.ts +477 -0
- package/src/scripts/_lib/config_cost.ts +209 -0
- package/src/scripts/_lib/corpus_manifest.ts +726 -0
- package/src/scripts/_lib/council_settings_block.ts +6 -0
- package/src/scripts/_lib/curator_ops.ts +172 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
- package/src/scripts/_lib/delivery_criticality.ts +126 -0
- package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
- package/src/scripts/_lib/empty_cycles.ts +88 -0
- package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
- package/src/scripts/_lib/eval_publication.ts +354 -0
- package/src/scripts/_lib/evaluation_cascade.ts +452 -0
- package/src/scripts/_lib/evaluation_vector.ts +283 -0
- package/src/scripts/_lib/evaluator_promotion.ts +225 -0
- package/src/scripts/_lib/evidence_basis.ts +118 -0
- package/src/scripts/_lib/evolution_roi.ts +562 -0
- package/src/scripts/_lib/exec_evidence.ts +8 -0
- package/src/scripts/_lib/experience_card.ts +272 -0
- package/src/scripts/_lib/experience_report.ts +151 -0
- package/src/scripts/_lib/experiment_freeze.ts +112 -0
- package/src/scripts/_lib/generated_by.ts +66 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
- package/src/scripts/_lib/hook_effect_probe.ts +141 -0
- package/src/scripts/_lib/host_denominator.ts +687 -0
- package/src/scripts/_lib/host_projection_reach.ts +157 -0
- package/src/scripts/_lib/ignored_blocker.ts +148 -0
- package/src/scripts/_lib/install_reach_checks.ts +495 -0
- package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
- package/src/scripts/_lib/judge_hygiene.ts +228 -0
- package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
- package/src/scripts/_lib/lexical_shortlist.ts +215 -0
- package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
- package/src/scripts/_lib/loop_guards.ts +299 -0
- package/src/scripts/_lib/loss_class.ts +129 -0
- package/src/scripts/_lib/machine_wake.ts +51 -0
- package/src/scripts/_lib/md_prose_lines.ts +177 -0
- package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
- package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
- package/src/scripts/_lib/orchestration_record.ts +253 -5
- package/src/scripts/_lib/outcome_envelope.ts +227 -0
- package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
- package/src/scripts/_lib/paired_stats.ts +245 -0
- package/src/scripts/_lib/paired_verdict.ts +226 -0
- package/src/scripts/_lib/pathology_archive.ts +393 -0
- package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
- package/src/scripts/_lib/privacy_class.ts +47 -0
- package/src/scripts/_lib/promotion_capability.ts +315 -0
- package/src/scripts/_lib/promotion_evidence.ts +414 -0
- package/src/scripts/_lib/promotion_review.ts +294 -0
- package/src/scripts/_lib/prompt_shape.ts +92 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
- package/src/scripts/_lib/release_highlights.ts +70 -1
- package/src/scripts/_lib/release_material.ts +125 -2
- package/src/scripts/_lib/repeated_failure.ts +105 -0
- package/src/scripts/_lib/repo_root.ts +111 -0
- package/src/scripts/_lib/review_skipped_record.ts +37 -0
- package/src/scripts/_lib/role_split.ts +338 -0
- package/src/scripts/_lib/routing_corpus.ts +307 -0
- package/src/scripts/_lib/routing_index_input.ts +104 -0
- package/src/scripts/_lib/rule_injection.ts +22 -1
- package/src/scripts/_lib/runtime_journal.ts +1499 -0
- package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
- package/src/scripts/_lib/semantic_noop.ts +167 -0
- package/src/scripts/_lib/skill_catalogue.ts +11 -1
- package/src/scripts/_lib/source_digest.ts +200 -0
- package/src/scripts/_lib/source_redact.ts +260 -0
- package/src/scripts/_lib/source_shape.ts +502 -0
- package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
- package/src/scripts/_lib/strip_comments.d.mts +8 -0
- package/src/scripts/_lib/strip_comments.mjs +65 -0
- package/src/scripts/_lib/test_red_state.ts +154 -0
- package/src/scripts/_lib/trigger_shift.ts +144 -0
- package/src/scripts/_lib/untrusted_content.ts +82 -7
- package/src/scripts/activation_receipt.ts +258 -0
- package/src/scripts/adoption_report.ts +1 -1
- package/src/scripts/adr/evidence_census.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +26 -2
- package/src/scripts/adr_cite_check.ts +164 -1
- package/src/scripts/ai_council/blind_review.ts +11 -1
- package/src/scripts/ai_council/clients.ts +4 -0
- package/src/scripts/ai_council/config.ts +3 -0
- package/src/scripts/ai_council/consensus.ts +28 -8
- package/src/scripts/ai_council/consensus_round.ts +226 -0
- package/src/scripts/ai_council/cross_exam.ts +128 -0
- package/src/scripts/ai_council/disagreement_signal.ts +338 -0
- package/src/scripts/ai_council/explain_route.ts +157 -0
- package/src/scripts/ai_council/information_gain.ts +293 -0
- package/src/scripts/ai_council/inline_findings.ts +340 -0
- package/src/scripts/ai_council/judge_position_bias.ts +197 -0
- package/src/scripts/ai_council/leakage_corpus.ts +385 -0
- package/src/scripts/ai_council/leakage_patterns.ts +453 -0
- package/src/scripts/ai_council/minority_retention.ts +171 -0
- package/src/scripts/ai_council/orchestrator.ts +16 -203
- package/src/scripts/ai_council/orchestrator_results.ts +23 -3
- package/src/scripts/ai_council/pricing.ts +106 -0
- package/src/scripts/ai_council/prompts.ts +74 -7
- package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
- package/src/scripts/ai_council/py_format.ts +14 -3
- package/src/scripts/ai_council/recouncil_guard.ts +293 -0
- package/src/scripts/ai_council/recouncil_savings.ts +299 -0
- package/src/scripts/ai_council/replay_route.ts +223 -0
- package/src/scripts/ai_council/response_record.ts +50 -0
- package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
- package/src/scripts/ai_council/routing_training_row.ts +197 -0
- package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
- package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
- package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
- package/src/scripts/asset_delivery_ledger.ts +157 -0
- package/src/scripts/attest_artifact.ts +193 -0
- package/src/scripts/audit_auto_rules.ts +2 -1
- package/src/scripts/audit_command_surface.ts +1 -1
- package/src/scripts/audit_mcp_tools.ts +2 -2
- package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
- package/src/scripts/audit_user_type_axis.ts +2 -1
- package/src/scripts/bench_ab_clone.ts +215 -10
- package/src/scripts/bench_ab_integrity.ts +119 -5
- package/src/scripts/bench_ab_v2_stats.ts +40 -213
- package/src/scripts/build_archive_index.ts +1 -1
- package/src/scripts/build_linear_digest.ts +1 -1
- package/src/scripts/build_proof.ts +11 -4
- package/src/scripts/build_rule_trigger_matrix.ts +1 -1
- package/src/scripts/build_source_digests.ts +157 -0
- package/src/scripts/cache_realization_report.ts +103 -0
- package/src/scripts/check_adr_frontmatter.ts +131 -10
- package/src/scripts/check_benchmark_report_fields.ts +207 -0
- package/src/scripts/check_beta_review_markers.ts +235 -6
- package/src/scripts/check_bundle_path_leakage.ts +34 -1
- package/src/scripts/check_claims.ts +576 -6
- package/src/scripts/check_composite_arming.ts +35 -0
- package/src/scripts/check_concern_admissions.ts +365 -0
- package/src/scripts/check_enforcement_coverage.ts +28 -0
- package/src/scripts/check_estate_count.ts +347 -25
- package/src/scripts/check_gate_reachability.ts +383 -0
- package/src/scripts/check_host_loadability.ts +104 -0
- package/src/scripts/check_loss_class_declared.ts +308 -0
- package/src/scripts/check_md_language.ts +15 -98
- package/src/scripts/check_memory_proposal.ts +18 -11
- package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
- package/src/scripts/check_no_external_sources.ts +281 -6
- package/src/scripts/check_pack_conformance_fixture.ts +11 -1
- package/src/scripts/check_pack_size.ts +59 -2
- package/src/scripts/check_preamble_payload_budget.ts +114 -3
- package/src/scripts/check_prefix_stable_mutation.ts +372 -0
- package/src/scripts/check_publish_surface.ts +10 -1
- package/src/scripts/check_references.ts +24 -1
- package/src/scripts/check_release_highlights.ts +96 -13
- package/src/scripts/check_roadmap_trackable.ts +17 -2
- package/src/scripts/check_rule_evidence_declaration.ts +316 -0
- package/src/scripts/check_rule_projection_integrity.ts +14 -4
- package/src/scripts/check_score_contract.ts +26 -3
- package/src/scripts/check_static_parity.ts +285 -0
- package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
- package/src/scripts/check_suppression_hygiene.ts +15 -0
- package/src/scripts/ci_settle.ts +39 -2
- package/src/scripts/code_graph/build.ts +60 -3
- package/src/scripts/code_graph/extract.ts +44 -0
- package/src/scripts/code_graph/types.ts +24 -0
- package/src/scripts/collector_daemon.ts +714 -0
- package/src/scripts/config_cost_report.ts +302 -0
- package/src/scripts/consumer_matrix.ts +74 -1
- package/src/scripts/corpus_manifest.ts +235 -0
- package/src/scripts/cost/budget.mjs +10 -3
- package/src/scripts/cost/track.mjs +10 -3
- package/src/scripts/council_cli.ts +37 -54
- package/src/scripts/dispatch_r2_reviewer.ts +46 -5
- package/src/scripts/evolution_lab.ts +1153 -0
- package/src/scripts/external_sources_denylist.json +5 -18
- package/src/scripts/extract_audit_patterns.ts +21 -0
- package/src/scripts/fold_intake.ts +12 -1
- package/src/scripts/gen_discovery_baseline.ts +1 -1
- package/src/scripts/generate_capabilities_index.ts +12 -5
- package/src/scripts/generate_capability_matrix.ts +3 -3
- package/src/scripts/generate_command_flows.ts +2 -2
- package/src/scripts/generate_cookbook.ts +2 -2
- package/src/scripts/generate_index.ts +8 -1
- package/src/scripts/generate_knowledge_index.ts +2 -1
- package/src/scripts/generate_ownership_matrix.ts +2 -1
- package/src/scripts/generate_pack_manifests.ts +10 -2
- package/src/scripts/generate_role_experiences_catalog.ts +2 -2
- package/src/scripts/generate_settings_reference.ts +1 -1
- package/src/scripts/git_authorization_hook.ts +22 -1
- package/src/scripts/grade_target_readiness.ts +48 -5
- package/src/scripts/hook_effect_doctor.ts +261 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +125 -16
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
- package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
- package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/dispatch_hook.ts +32 -0
- package/src/scripts/hooks/journal_record_hook.ts +345 -0
- package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
- package/src/scripts/hooks/run_continuation_hook.ts +44 -9
- package/src/scripts/hooks/shims/install.sh +61 -0
- package/src/scripts/hooks/shims/php +101 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
- package/src/scripts/hot_context_hook.ts +16 -0
- package/src/scripts/install-hooks.sh +20 -5
- package/src/scripts/install.ts +17 -35
- package/src/scripts/inventory_frontmatter.ts +2 -1
- package/src/scripts/language_mirror_hook.ts +14 -2
- package/src/scripts/lint_adr_sweep_routing.ts +12 -0
- package/src/scripts/lint_canonical_terms.ts +604 -0
- package/src/scripts/lint_carrier_integrity.ts +820 -0
- package/src/scripts/lint_code_comments.ts +643 -0
- package/src/scripts/lint_composition_review.ts +619 -0
- package/src/scripts/lint_consolidation_lineage.ts +666 -0
- package/src/scripts/lint_eval_specs.ts +593 -0
- package/src/scripts/lint_hook_manifest.ts +19 -0
- package/src/scripts/lint_host_portability.ts +373 -0
- package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
- package/src/scripts/lint_memory_twin_parity.ts +335 -0
- package/src/scripts/lint_metric_consumers.ts +355 -0
- package/src/scripts/lint_plan_risk_register.ts +39 -19
- package/src/scripts/lint_promotion_paths.ts +779 -0
- package/src/scripts/lint_skill_descriptions.ts +18 -1
- package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
- package/src/scripts/lint_skill_link_reach.ts +252 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
- package/src/scripts/lint_ticket_buildable.ts +17 -1
- package/src/scripts/llm_propose.ts +256 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
- package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
- package/src/scripts/measure_delivery_sets.ts +361 -0
- package/src/scripts/measure_docs_dead_links.ts +348 -0
- package/src/scripts/measure_host_capture.ts +461 -0
- package/src/scripts/measure_routing_signal.ts +307 -0
- package/src/scripts/migration_status.ts +3 -3
- package/src/scripts/model_rule_injection.ts +76 -0
- package/src/scripts/orchestration_record.ts +14 -0
- package/src/scripts/preamble_byte_census.ts +139 -10
- package/src/scripts/prepack-check.mjs +4 -1
- package/src/scripts/probe_council_retention.ts +495 -0
- package/src/scripts/probe_turnaround.ts +384 -0
- package/src/scripts/probe_unblocked_ask.ts +279 -0
- package/src/scripts/release.ts +21 -37
- package/src/scripts/release_drill.ts +143 -0
- package/src/scripts/release_env.ts +35 -0
- package/src/scripts/release_publication.ts +84 -0
- package/src/scripts/render_benchmark_md.ts +1 -1
- package/src/scripts/rule_activation_census.ts +70 -9
- package/src/scripts/rule_backlinks.ts +1 -1
- package/src/scripts/run_lifecycle_suite.ts +208 -0
- package/src/scripts/run_skill_evals.ts +40 -0
- package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
- package/src/scripts/schemas/drafting-channels.schema.json +43 -0
- package/src/scripts/schemas/evals.schema.json +24 -1
- package/src/scripts/schemas/rule.schema.json +52 -1
- package/src/scripts/schemas/skill.schema.json +17 -2
- package/src/scripts/skill_overlap.ts +7 -1
- package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
- package/src/scripts/skill_usage_report.ts +2 -1
- package/src/scripts/stubs_due.ts +211 -0
- package/src/scripts/sweep_source_surfaces.ts +678 -0
- package/src/scripts/sync_pr_branch.ts +3 -3
- package/src/scripts/trigger_eval_grandfather.json +202 -222
- package/src/scripts/utilization_report.ts +22 -2
- package/src/server/schemas/settings.ts +5 -0
- package/src/templates/marketing-copy.yml +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +0 -26
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PreToolUse guard: refuse the CREATION of a speaking inbox directory under
|
|
4
|
+
* `agents/tmp/` — `road-to-source-silence` Phase 4.2.
|
|
5
|
+
*
|
|
6
|
+
* ## Why a write-time guard, when the directory is gitignored anyway
|
|
7
|
+
*
|
|
8
|
+
* `agents/tmp/` is gitignored, so a speaking round directory looks free. It is
|
|
9
|
+
* the root of the whole leak chain and the chain is measured, not theorised:
|
|
10
|
+
* the name gets quoted into a tracked roadmap `> **Source:**` header, into an
|
|
11
|
+
* evidence artefact, into a review-snapshot FILENAME and into a PR body — and
|
|
12
|
+
* every one of those quotes republishes it in a public repository. Phase 0's
|
|
13
|
+
* census counted **190 block-tier occurrences** of quoted non-opaque
|
|
14
|
+
* `agents/tmp(.old)/<name>/` paths across the tracked tree, plus one tracked
|
|
15
|
+
* findings file named after a round.
|
|
16
|
+
*
|
|
17
|
+
* Every downstream gate in this programme catches the QUOTE. This one catches
|
|
18
|
+
* the name, at the only moment removing it is free: before anything can cite
|
|
19
|
+
* it. Renaming after the first quote lands means chasing the quotes.
|
|
20
|
+
*
|
|
21
|
+
* ## What it refuses, and the four things it does not
|
|
22
|
+
*
|
|
23
|
+
* Refuses: a Write/Edit/NotebookEdit (or cross-platform equivalent) whose
|
|
24
|
+
* target path introduces a **new** first-level directory under `agents/tmp/`
|
|
25
|
+
* or `agents/tmp.old/` whose name is not an opaque round identifier.
|
|
26
|
+
*
|
|
27
|
+
* Allowed, deliberately:
|
|
28
|
+
*
|
|
29
|
+
* 1. **A file directly under `agents/tmp/`** with no subdirectory. Scratch
|
|
30
|
+
* files are not rounds and have no name to leak.
|
|
31
|
+
* 2. **A directory that already exists.** Blocking every later write into an
|
|
32
|
+
* already-created speaking directory would wedge a session mid-round without
|
|
33
|
+
* removing the name — the fix there is a rename, which the deny message of
|
|
34
|
+
* the creating call already asked for. This is the one filesystem read the
|
|
35
|
+
* guard performs.
|
|
36
|
+
* 3. **An opaque round identifier** — `isOpaqueRoundId` in
|
|
37
|
+
* `_lib/source_shape.ts` is the single authority, shared with the gate, so
|
|
38
|
+
* the guard and the CI check can never disagree about what "opaque" means.
|
|
39
|
+
* 4. **A named working set** — `NON_HARVEST_TMP_DIRS`, same shared module. A
|
|
40
|
+
* directory named after the WORK leaks nothing; the precedent
|
|
41
|
+
* (`bench-local`) was added on a measured false positive.
|
|
42
|
+
*
|
|
43
|
+
* ## Severity, stated honestly
|
|
44
|
+
*
|
|
45
|
+
* `severity: blocking` with `fail_closed: false`. A DETECTED violation refuses;
|
|
46
|
+
* a malformed envelope, an unreadable path or any crash ALLOWS. That pairing is
|
|
47
|
+
* deliberate and copied from `block_config_weakening`: the guarantee is about
|
|
48
|
+
* the case the guard actually decided, and a scratch-directory guard must never
|
|
49
|
+
* be the reason an unrelated edit fails. Kill switch for a maintainer who needs
|
|
50
|
+
* it out of the way: `AGENT_CONFIG_ALLOW_SPEAKING_INBOX=1`.
|
|
51
|
+
*
|
|
52
|
+
* Only `claude` both binds `pre_tool_use` and honours a deny. Elsewhere this
|
|
53
|
+
* runs and is ignored, or does not bind at all — `agent-config hooks:status`
|
|
54
|
+
* answers it for the host you are on, and this docstring does not claim
|
|
55
|
+
* otherwise.
|
|
56
|
+
*
|
|
57
|
+
* Exit codes (docs/contracts/hook-architecture-v1.md): 0 allow · 1 block.
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
import * as fs from 'node:fs';
|
|
61
|
+
import * as path from 'node:path';
|
|
62
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
63
|
+
|
|
64
|
+
import { isNonHarvestTmpDir, isOpaqueRoundId } from '../_lib/source_shape.js';
|
|
65
|
+
import { readHookStdin } from './hook_stdin.js';
|
|
66
|
+
|
|
67
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
68
|
+
|
|
69
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | { [k: string]: JsonValue };
|
|
70
|
+
type JsonObject = { [k: string]: JsonValue };
|
|
71
|
+
|
|
72
|
+
const KILL_SWITCH = 'AGENT_CONFIG_ALLOW_SPEAKING_INBOX';
|
|
73
|
+
|
|
74
|
+
/** Keys across platforms that carry a tool call's target file path. */
|
|
75
|
+
const _PATH_KEYS: readonly string[] = [
|
|
76
|
+
'file_path', 'path', 'target_file', 'filename', 'filePath', 'notebook_path',
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
function _isObject(v: JsonValue | undefined): v is JsonObject {
|
|
80
|
+
return v !== null && v !== undefined && typeof v === 'object' && !Array.isArray(v);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** `agents/tmp/<name>/…` or `agents/tmp.old/<name>/…`, after normalisation. */
|
|
84
|
+
const INBOX_RE = /(?:^|\/)agents\/tmp(?:\.old)?\/([^/]+)\/./;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A DIRECTORY-TERMINAL inbox path — `agents/tmp/<name>` with nothing after it.
|
|
88
|
+
*
|
|
89
|
+
* `mkdir -p agents/tmp/<name>` names the directory with no trailing slash and no
|
|
90
|
+
* file after it, so `INBOX_RE` cannot see it. That is the exact bypass the R2
|
|
91
|
+
* review of this branch found, and the test that pins it caught this second
|
|
92
|
+
* form on the first run.
|
|
93
|
+
*
|
|
94
|
+
* The last segment is read as a DIRECTORY only when it carries no `.` — so
|
|
95
|
+
* `cat agents/tmp/scratch.ts` stays a file reference and is not judged as a
|
|
96
|
+
* round name. That is a heuristic and its limit is real: a directory whose name
|
|
97
|
+
* genuinely contains a dot is missed by this form. It is still caught the moment
|
|
98
|
+
* anything is written INSIDE it, which is the path `INBOX_RE` covers.
|
|
99
|
+
*/
|
|
100
|
+
const INBOX_DIR_TERMINAL_RE = /(?:^|\/)agents\/tmp(?:\.old)?\/([^/.]+)\/?$/;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The first-level directory name this path would place a file under, or `null`
|
|
104
|
+
* when the path is not inside an inbox subdirectory at all.
|
|
105
|
+
*
|
|
106
|
+
* Pure, and separated from the filesystem check so the decision is testable
|
|
107
|
+
* without a tree — the shape half of the guard is what a harness can pin.
|
|
108
|
+
*/
|
|
109
|
+
export function inboxDirName(filePath: string): string | null {
|
|
110
|
+
if (!filePath) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const normalized = filePath.replace(/\\/g, '/').replace(/^(\.\/)+/, '');
|
|
114
|
+
const m = INBOX_RE.exec(normalized);
|
|
115
|
+
if (m) {
|
|
116
|
+
return m[1] as string;
|
|
117
|
+
}
|
|
118
|
+
const d = INBOX_DIR_TERMINAL_RE.exec(normalized);
|
|
119
|
+
return d ? (d[1] as string) : null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Is this directory name one the confidentiality contract accepts?
|
|
124
|
+
*
|
|
125
|
+
* Delegates entirely to the shared shape module, so "opaque" means exactly what
|
|
126
|
+
* `check_no_external_sources` means by it.
|
|
127
|
+
*/
|
|
128
|
+
export function isAcceptableInboxDir(name: string): boolean {
|
|
129
|
+
return isOpaqueRoundId(name) || isNonHarvestTmpDir(name);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The guard's verdict for one target path. `existsSync` is injected so the
|
|
134
|
+
* harness can pin the already-exists branch without touching a real tree.
|
|
135
|
+
*/
|
|
136
|
+
export function verdictFor(
|
|
137
|
+
filePath: string,
|
|
138
|
+
exists: (p: string) => boolean,
|
|
139
|
+
repoRoot = '',
|
|
140
|
+
): { block: boolean; dir: string | null; reason: string } {
|
|
141
|
+
const dir = inboxDirName(filePath);
|
|
142
|
+
if (dir === null) {
|
|
143
|
+
return { block: false, dir: null, reason: 'not inside an inbox subdirectory' };
|
|
144
|
+
}
|
|
145
|
+
if (isAcceptableInboxDir(dir)) {
|
|
146
|
+
return { block: false, dir, reason: 'opaque round identifier or named working set' };
|
|
147
|
+
}
|
|
148
|
+
// Already created — a rename is the fix, and refusing every later write
|
|
149
|
+
// would wedge the round without removing the name.
|
|
150
|
+
//
|
|
151
|
+
// The probe path is derived from the SAME anchored match that found the
|
|
152
|
+
// directory, not from `indexOf('agents/tmp')`. That prefix also matches
|
|
153
|
+
// `agents/tmp-notes/` and `agents/tmpfiles/`, and taking the FIRST
|
|
154
|
+
// occurrence meant a path carrying a decoy earlier segment probed the wrong
|
|
155
|
+
// directory — in either direction. Found by the R2 review of this branch.
|
|
156
|
+
const normalized = filePath.replace(/\\/g, '/').replace(/^(\.\/)+/, '');
|
|
157
|
+
const m =
|
|
158
|
+
/(?:^|\/)(agents\/tmp(?:\.old)?\/[^/]+)\//.exec(normalized) ??
|
|
159
|
+
/(?:^|\/)(agents\/tmp(?:\.old)?\/[^/.]+)\/?$/.exec(normalized);
|
|
160
|
+
if (m === null) {
|
|
161
|
+
// `inboxDirName` matched but this did not — treat as unattributable and
|
|
162
|
+
// BLOCK, since the name is speaking and we cannot prove it pre-exists.
|
|
163
|
+
return { block: true, dir, reason: 'new inbox directory with a speaking name (path not re-anchorable)' };
|
|
164
|
+
}
|
|
165
|
+
const upto = m[1] as string;
|
|
166
|
+
const probe = repoRoot === '' ? upto : path.join(repoRoot, upto);
|
|
167
|
+
if (exists(probe)) {
|
|
168
|
+
return { block: false, dir, reason: 'directory already exists — rename, do not re-refuse' };
|
|
169
|
+
}
|
|
170
|
+
return { block: true, dir, reason: 'new inbox directory with a speaking name' };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** The deny message — names the rule, the fix and the accepted forms. */
|
|
174
|
+
export function denyMessage(dir: string): string {
|
|
175
|
+
return (
|
|
176
|
+
`block-speaking-inbox-dir: BLOCKED — creating \`agents/tmp/${dir}/\` would name an\n` +
|
|
177
|
+
'inbox round after its source. That name is the root of the leak chain: it gets\n' +
|
|
178
|
+
'quoted into tracked roadmap `Source:` headers, evidence artefacts, review-snapshot\n' +
|
|
179
|
+
'filenames and PR bodies, and every quote republishes it in a public repository.\n' +
|
|
180
|
+
'\n' +
|
|
181
|
+
'Use an opaque round identifier instead:\n' +
|
|
182
|
+
' inbox-2026-08-h round-dated, optional 1-3 char disambiguator\n' +
|
|
183
|
+
' round-a91f3c content-free hex (also set-, src-set-, source-set-)\n' +
|
|
184
|
+
' S17 a set number\n' +
|
|
185
|
+
'\n' +
|
|
186
|
+
'Record the true source ONCE, encrypted, in the round\'s intake note:\n' +
|
|
187
|
+
" printf '%s' '<the real source>' | ./scripts-run src/scripts/_lib/link_crypto encrypt\n" +
|
|
188
|
+
'\n' +
|
|
189
|
+
'Naming rule: /analyze:inbox Phase 1. Rule: src/rules/source-confidentiality.md.\n' +
|
|
190
|
+
`Maintainer kill switch: ${KILL_SWITCH}=1.\n`
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function main(): number {
|
|
195
|
+
if ((process.env[KILL_SWITCH] ?? '') !== '') {
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
let envelope: JsonObject;
|
|
199
|
+
try {
|
|
200
|
+
const raw = readHookStdin();
|
|
201
|
+
if (!raw) {
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
envelope = JSON.parse(raw) as JsonObject;
|
|
205
|
+
} catch {
|
|
206
|
+
return 0; // fail_closed: false — a malformed envelope never blocks.
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
const payload = _isObject(envelope['payload']) ? envelope['payload'] : envelope;
|
|
210
|
+
const ti = _isObject(payload['tool_input'])
|
|
211
|
+
? payload['tool_input']
|
|
212
|
+
: _isObject(envelope['tool_input'])
|
|
213
|
+
? envelope['tool_input']
|
|
214
|
+
: null;
|
|
215
|
+
if (ti === null) {
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
const repoRoot = typeof envelope['project_dir'] === 'string' ? envelope['project_dir'] : '';
|
|
219
|
+
const candidates: string[] = [];
|
|
220
|
+
for (const key of _PATH_KEYS) {
|
|
221
|
+
const v = ti[key];
|
|
222
|
+
if (typeof v === 'string' && v) {
|
|
223
|
+
candidates.push(v);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// A shell command creates the directory just as effectively as a Write,
|
|
227
|
+
// and this guard read only the path keys — so `mkdir -p
|
|
228
|
+
// agents/tmp/<speaking-name>`, a `git mv` into one, or a redirect
|
|
229
|
+
// bypassed it entirely. Both siblings on this slot (`block_no_verify`,
|
|
230
|
+
// `block_kernel_rule_writes`) parse the command string; this one did
|
|
231
|
+
// not, and the R2 review of this branch caught it. Every whitespace
|
|
232
|
+
// token of the command is offered to the same pure verdict, so the
|
|
233
|
+
// decision logic is shared rather than duplicated.
|
|
234
|
+
const cmd = ti['command'] ?? (_isObject(envelope['payload']) ? (envelope['payload'] as JsonObject)['command'] : undefined);
|
|
235
|
+
if (typeof cmd === 'string' && cmd) {
|
|
236
|
+
for (const tok of cmd.split(/[\s"'`(){};|&<>]+/)) {
|
|
237
|
+
if (tok) {
|
|
238
|
+
candidates.push(tok);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
for (const v of candidates) {
|
|
243
|
+
const verdict = verdictFor(v, (p) => fs.existsSync(p), repoRoot);
|
|
244
|
+
if (verdict.block && verdict.dir !== null) {
|
|
245
|
+
process.stderr.write(denyMessage(verdict.dir));
|
|
246
|
+
return 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
} catch {
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
return 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function _isCliEntry(): boolean {
|
|
256
|
+
if (process.argv[1] === undefined) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
264
|
+
} catch {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (_isCliEntry()) {
|
|
270
|
+
process.exit(main());
|
|
271
|
+
}
|
|
@@ -523,6 +523,24 @@ export function commandOp(command: string): GitOp | null {
|
|
|
523
523
|
* window grows. The agent never edits this constant, this file, or the built
|
|
524
524
|
* bundle; `dist/hooks/dispatch.js` is what actually executes, and a source
|
|
525
525
|
* edit without a rebuild is silently inert.
|
|
526
|
+
*
|
|
527
|
+
* **ADR-251 (2026-08-30) decided this question and KEPT the value.** An AI
|
|
528
|
+
* council converged 2/2 on a different authorization SHAPE rather than a wider
|
|
529
|
+
* window, against the measured pressure that 7 of the 10 most recent sessions
|
|
530
|
+
* of this package outlive a 30-minute window (median span 3.1 h) and that the
|
|
531
|
+
* constant has been hand-widened twice. `LEDGER_MAX_AGE_MS` is unchanged at 30
|
|
532
|
+
* minutes and raising it remains forbidden — that transition is owner-reserved,
|
|
533
|
+
* and this record did not take it.
|
|
534
|
+
*
|
|
535
|
+
* What the record DID change is the behaviour at expiry: the run PAUSES,
|
|
536
|
+
* reports the remaining work, and ASKS for re-authorization, instead of ending.
|
|
537
|
+
* The user's reply renews this ledger through the path that already exists —
|
|
538
|
+
* `git_authorization_hook.ts` rewrites the session's ledger with a fresh
|
|
539
|
+
* `detected_at` on every human-typed prompt (`:512-537`), so a mid-run reply
|
|
540
|
+
* carrying an authorization phrase resets the age this constant is compared
|
|
541
|
+
* against. No new machinery, and the signal stays agent-unforgeable.
|
|
542
|
+
*
|
|
543
|
+
* See `docs/decisions/ADR-251-authorization-window-shape-not-width.md`.
|
|
526
544
|
*/
|
|
527
545
|
export const LEDGER_MAX_AGE_MS = 30 * 60 * 1000;
|
|
528
546
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Comment-discipline advisory — `post_tool_use` concern.
|
|
4
|
+
*
|
|
5
|
+
* The write-time half of `lint_code_comments`. The gate answers "may this
|
|
6
|
+
* land"; this answers "was it written that way in the first place", which is
|
|
7
|
+
* the question the maintainer actually asked after a run produced 509 German
|
|
8
|
+
* comment lines across 41 of 45 changed source files without anything
|
|
9
|
+
* objecting once.
|
|
10
|
+
*
|
|
11
|
+
* `code-comment-discipline` is `type: auto` with PROMPT keywords (`comment`,
|
|
12
|
+
* `refactor`, `implement`, …). A run that writes forty-five files while the
|
|
13
|
+
* user says "build the todo module" matches none of them, so the rule never
|
|
14
|
+
* loads — the activation gap `fix-what-you-see` names for itself, in the one
|
|
15
|
+
* place where the agent is producing the artefact the rule governs. A
|
|
16
|
+
* post-write concern fires on the TOOL EVENT and therefore does not depend on
|
|
17
|
+
* what the prompt happened to say.
|
|
18
|
+
*
|
|
19
|
+
* `Write` carries the new content in `tool_input.content`; `Edit` carries the
|
|
20
|
+
* replacement in `tool_input.new_string`. Scanning that text rather than the
|
|
21
|
+
* file on disk makes the concern forward-only by construction: a pre-existing
|
|
22
|
+
* comment the edit did not touch cannot fire it, so there is no baseline to
|
|
23
|
+
* maintain and no legacy tree to clean before turning it on.
|
|
24
|
+
*
|
|
25
|
+
* Same shape as `edit_shape_hook.ts` and `delegation_nudge_hook.ts`:
|
|
26
|
+
* `host_semantics.emitFor`'s `severity === "warn"` branch returns exit 0 with
|
|
27
|
+
* the text in `hookSpecificOutput.additionalContext`, unconditionally, so the
|
|
28
|
+
* byte handed to the host is always 0. Advisory is the right severity here
|
|
29
|
+
* and not a hedge — the classifier is a line heuristic, and a heuristic that
|
|
30
|
+
* can refuse a write would turn one false positive into a blocked session.
|
|
31
|
+
* The deterministic refusal lives in the gate, where a human can read the
|
|
32
|
+
* whole file before answering.
|
|
33
|
+
*
|
|
34
|
+
* `edit-shape` fires once per session because its advice is a habit
|
|
35
|
+
* correction that lands the first time. This one is per-write on purpose: the
|
|
36
|
+
* measured failure is forty-one files each carrying the defect, and a nudge
|
|
37
|
+
* that speaks once and then watches forty more land is the shape that
|
|
38
|
+
* produced the incident. The cost is bounded by naming at most
|
|
39
|
+
* `MAX_REPORTED` findings and no more than one line per write.
|
|
40
|
+
*
|
|
41
|
+
* ROBUSTNESS: malformed payload → exit 0 silently. This concern never blocks.
|
|
42
|
+
*/
|
|
43
|
+
import * as fs from 'node:fs';
|
|
44
|
+
import * as path from 'node:path';
|
|
45
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
46
|
+
|
|
47
|
+
import { isScannable, scanText, type CommentFinding } from '../lint_code_comments.js';
|
|
48
|
+
import { unwrap, type JsonObject, type JsonValue } from './envelope.js';
|
|
49
|
+
import { readHookStdin } from './hook_stdin.js';
|
|
50
|
+
|
|
51
|
+
const EXIT_ALLOW = 0;
|
|
52
|
+
const EXIT_WARN = 2;
|
|
53
|
+
|
|
54
|
+
/** Findings named in the advisory line. The rest are counted, never listed. */
|
|
55
|
+
export const MAX_REPORTED = 3;
|
|
56
|
+
|
|
57
|
+
function str(v: JsonValue | undefined): string {
|
|
58
|
+
return typeof v === 'string' ? v : '';
|
|
59
|
+
}
|
|
60
|
+
function isObject(v: unknown): v is JsonObject {
|
|
61
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The written text, per tool. Empty string when the payload carries none. */
|
|
65
|
+
export function writtenText(toolName: string, toolInput: JsonObject): string {
|
|
66
|
+
if (toolName === 'Write') return str(toolInput['content'] as JsonValue | undefined);
|
|
67
|
+
if (toolName === 'Edit') {
|
|
68
|
+
return str(toolInput['new_string'] as JsonValue | undefined)
|
|
69
|
+
|| str(toolInput['newString'] as JsonValue | undefined);
|
|
70
|
+
}
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** One advisory line, naming what fired and where. */
|
|
75
|
+
export function buildAdvisoryLine(file: string, findings: readonly CommentFinding[]): string {
|
|
76
|
+
const counts = new Map<string, number>();
|
|
77
|
+
for (const f of findings) counts.set(f.cls, (counts.get(f.cls) ?? 0) + 1);
|
|
78
|
+
const summary = [...counts].map(([c, n]) => `${c} ×${n}`).join(' · ');
|
|
79
|
+
const named = findings.slice(0, MAX_REPORTED)
|
|
80
|
+
.map((f) => `line ${f.line} (${f.signal})`)
|
|
81
|
+
.join(', ');
|
|
82
|
+
const more = findings.length > MAX_REPORTED ? `, +${findings.length - MAX_REPORTED} more` : '';
|
|
83
|
+
return (
|
|
84
|
+
`comment-discipline: the text just written to ${file} carries ${summary} — ${named}${more}. `
|
|
85
|
+
+ 'A comment states a WHY or a constraint the code cannot show, in English; evidence for a '
|
|
86
|
+
+ 'roadmap step belongs in that roadmap, not in a second copy in the source. Rewrite or '
|
|
87
|
+
+ 'delete those lines now, before the next write — `lint_code_comments` refuses them at the gate.'
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function main(): number {
|
|
92
|
+
try {
|
|
93
|
+
const [envelope, payload] = unwrap(readHookStdin(), 'claude');
|
|
94
|
+
|
|
95
|
+
const event = str(envelope['event'] as JsonValue | undefined);
|
|
96
|
+
if (event !== '' && event !== 'post_tool_use') return EXIT_ALLOW;
|
|
97
|
+
|
|
98
|
+
const toolName = str(
|
|
99
|
+
(payload['tool_name'] ?? payload['toolName'] ?? payload['tool']) as JsonValue | undefined,
|
|
100
|
+
);
|
|
101
|
+
if (toolName !== 'Write' && toolName !== 'Edit') return EXIT_ALLOW;
|
|
102
|
+
|
|
103
|
+
const ti = payload['tool_input'] ?? payload['toolInput'] ?? payload['input'];
|
|
104
|
+
if (!isObject(ti)) return EXIT_ALLOW;
|
|
105
|
+
|
|
106
|
+
const filePath = str((ti['file_path'] ?? ti['path'] ?? ti['filePath']) as JsonValue | undefined);
|
|
107
|
+
if (!filePath || !isScannable(filePath)) return EXIT_ALLOW;
|
|
108
|
+
|
|
109
|
+
const text = writtenText(toolName, ti);
|
|
110
|
+
if (!text) return EXIT_ALLOW;
|
|
111
|
+
|
|
112
|
+
const workspaceRoot = str(envelope['workspace_root'] as JsonValue | undefined).trim() || process.cwd();
|
|
113
|
+
const abs = path.isAbsolute(filePath) ? filePath : path.resolve(workspaceRoot, filePath);
|
|
114
|
+
const rel = path.relative(workspaceRoot, abs);
|
|
115
|
+
const shown = rel.startsWith('..') ? path.basename(abs) : rel;
|
|
116
|
+
|
|
117
|
+
const findings = scanText(shown, text);
|
|
118
|
+
if (findings.length === 0) return EXIT_ALLOW;
|
|
119
|
+
|
|
120
|
+
process.stdout.write(
|
|
121
|
+
`${JSON.stringify({
|
|
122
|
+
decision: 'warn',
|
|
123
|
+
reason: `comment-discipline: ${findings.length} comment finding(s) in the text written to ${shown}`,
|
|
124
|
+
additional_context: buildAdvisoryLine(shown, findings),
|
|
125
|
+
})}\n`,
|
|
126
|
+
);
|
|
127
|
+
return EXIT_WARN;
|
|
128
|
+
} catch {
|
|
129
|
+
return EXIT_ALLOW;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
|
|
134
|
+
function _isCliEntry(): boolean {
|
|
135
|
+
if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
|
|
136
|
+
if (process.argv[1] === undefined) return false;
|
|
137
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
138
|
+
if (import.meta.url === argvUrl) return true;
|
|
139
|
+
try {
|
|
140
|
+
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (_isCliEntry()) process.exit(main());
|
|
@@ -53,6 +53,7 @@ import { main as evidenceIndependenceMain } from './evidence_independence.js';
|
|
|
53
53
|
import { main as blockNoVerifyMain } from './block_no_verify.js';
|
|
54
54
|
import { main as blockKernelRuleWritesMain } from './block_kernel_rule_writes.js';
|
|
55
55
|
import { main as blockConfigWeakeningMain } from './block_config_weakening.js';
|
|
56
|
+
import { main as blockSpeakingInboxDirMain } from './block_speaking_inbox_dir.js';
|
|
56
57
|
import { main as rtkWrapMain } from './rtk_wrap_hook.js';
|
|
57
58
|
import { _main as designPassMain } from './design_pass_hook.js';
|
|
58
59
|
import { main as designSlopMain } from './design_slop_hook.js';
|
|
@@ -68,6 +69,7 @@ import { main as ruleInjectMain } from './rule_inject_hook.js';
|
|
|
68
69
|
import { main as endReviewNudgeMain } from './end_review_nudge_hook.js';
|
|
69
70
|
import { main as turnEndGateMain } from './turn_end_gate_hook.js';
|
|
70
71
|
import { main as editShapeMain } from './edit_shape_hook.js';
|
|
72
|
+
import { main as commentDisciplineMain } from './comment_discipline_hook.js';
|
|
71
73
|
import { main as rereadGuardMain } from './reread_guard_hook.js';
|
|
72
74
|
import { main as sessionEolMain } from './session_eol_hook.js';
|
|
73
75
|
import { main as subagentLedgerMain } from './subagent_ledger_hook.js';
|
|
@@ -76,6 +78,7 @@ import { main as spawnGuardShadowMain } from './spawn_guard_shadow_hook.js';
|
|
|
76
78
|
import { main as sourceFirstGateMain } from './source_first_gate_hook.js';
|
|
77
79
|
import { main as interruptionLedgerMain } from './interruption_ledger_hook.js';
|
|
78
80
|
import { main as runContinuationMain } from './run_continuation_hook.js';
|
|
81
|
+
import { main as journalRecordMain } from './journal_record_hook.js';
|
|
79
82
|
|
|
80
83
|
/** A concern `main` — argv-taking or not; both shapes exist. */
|
|
81
84
|
export type ConcernMain = (argv?: string[]) => number | undefined | void;
|
|
@@ -111,6 +114,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
|
|
|
111
114
|
'src/scripts/hooks/block_no_verify.ts': blockNoVerifyMain as ConcernMain,
|
|
112
115
|
'src/scripts/hooks/block_kernel_rule_writes.ts': blockKernelRuleWritesMain as ConcernMain,
|
|
113
116
|
'src/scripts/hooks/block_config_weakening.ts': blockConfigWeakeningMain as ConcernMain,
|
|
117
|
+
'src/scripts/hooks/block_speaking_inbox_dir.ts': blockSpeakingInboxDirMain as ConcernMain,
|
|
114
118
|
'src/scripts/hooks/rtk_wrap_hook.ts': rtkWrapMain as ConcernMain,
|
|
115
119
|
'src/scripts/hooks/design_pass_hook.ts': designPassMain as ConcernMain,
|
|
116
120
|
'src/scripts/hooks/design_slop_hook.ts': designSlopMain as ConcernMain,
|
|
@@ -126,6 +130,7 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
|
|
|
126
130
|
'src/scripts/hooks/end_review_nudge_hook.ts': endReviewNudgeMain as ConcernMain,
|
|
127
131
|
'src/scripts/hooks/turn_end_gate_hook.ts': turnEndGateMain as ConcernMain,
|
|
128
132
|
'src/scripts/hooks/edit_shape_hook.ts': editShapeMain as ConcernMain,
|
|
133
|
+
'src/scripts/hooks/comment_discipline_hook.ts': commentDisciplineMain as ConcernMain,
|
|
129
134
|
'src/scripts/hooks/reread_guard_hook.ts': rereadGuardMain as ConcernMain,
|
|
130
135
|
'src/scripts/hooks/session_eol_hook.ts': sessionEolMain as ConcernMain,
|
|
131
136
|
'src/scripts/hooks/subagent_ledger_hook.ts': subagentLedgerMain as ConcernMain,
|
|
@@ -134,4 +139,5 @@ export const CONCERN_REGISTRY: Readonly<Record<string, ConcernMain>> = {
|
|
|
134
139
|
'src/scripts/hooks/source_first_gate_hook.ts': sourceFirstGateMain as ConcernMain,
|
|
135
140
|
'src/scripts/hooks/interruption_ledger_hook.ts': interruptionLedgerMain as ConcernMain,
|
|
136
141
|
'src/scripts/hooks/run_continuation_hook.ts': runContinuationMain as ConcernMain,
|
|
142
|
+
'src/scripts/hooks/journal_record_hook.ts': journalRecordMain as ConcernMain,
|
|
137
143
|
};
|
|
@@ -57,6 +57,7 @@ import { stdinReadFailure, denyOnStdinFailure } from './stdin_failure_policy.js'
|
|
|
57
57
|
export { stdinReadFailure, denyOnStdinFailure, _is_fail_closed_blocking } from './stdin_failure_policy.js';
|
|
58
58
|
import { _py_json_dumps } from './py_json_dumps.js';
|
|
59
59
|
import { _fallback_yaml } from './fallback_yaml.js';
|
|
60
|
+
import { recordCapture, recordOpportunity } from "../_lib/collector_denominator.js";
|
|
60
61
|
export { _fallback_yaml } from './fallback_yaml.js';
|
|
61
62
|
|
|
62
63
|
// Free-form JSON values flow through every helper here; a documented
|
|
@@ -1144,6 +1145,37 @@ export function main(argv?: string[]): number {
|
|
|
1144
1145
|
return EXIT_ALLOW; // fail-open per contract for unknown events
|
|
1145
1146
|
}
|
|
1146
1147
|
|
|
1148
|
+
// ── The capture rate: both halves, written here ─────────────────────────────
|
|
1149
|
+
//
|
|
1150
|
+
// Two calls rather than one, because they must be able to FAIL DIFFERENTLY.
|
|
1151
|
+
// `recordOpportunity` is the denominator's independent writer — in-process,
|
|
1152
|
+
// no daemon — so a dead collector yields a climbing denominator against a
|
|
1153
|
+
// flat numerator and the rate falls instead of reading 0/0. `recordCapture`
|
|
1154
|
+
// is the numerator, and its absence was a real defect three review rounds
|
|
1155
|
+
// took to find. Both are gated on the opt-in marker, both refuse a
|
|
1156
|
+
// self-observed dispatch, and neither throws; the rationale, the ordering and
|
|
1157
|
+
// the exclusion all live in `collector_denominator.ts`.
|
|
1158
|
+
//
|
|
1159
|
+
// UNGUARDED HERE, and that is finding 3 of round 4. The guard used to be
|
|
1160
|
+
// `if (!isSelfObservation())` around these two lines — and vitest always sets
|
|
1161
|
+
// `VITEST`, so under the parity comparison NEITHER run ever reached them.
|
|
1162
|
+
// `check_static_parity` could observe a module-load difference and nothing
|
|
1163
|
+
// else, which made the AC-7 comparison vacuous with respect to the thing it
|
|
1164
|
+
// claims to compare. The exclusion is a property of the METRIC, so it belongs
|
|
1165
|
+
// inside the metric functions where the opt-in check already is; putting it
|
|
1166
|
+
// in the caller's control flow is what made the calls disappear.
|
|
1167
|
+
//
|
|
1168
|
+
// Cost on a default-off install: FOUR `existsSync` calls, not two — each
|
|
1169
|
+
// function calls `isCollectorEnabled`, which probes the opt-out marker and
|
|
1170
|
+
// then the ENABLED one. The number is stated correctly here at the third
|
|
1171
|
+
// attempt (R2 finding 14 corrected one to two, round 4 finding 9 caught that
|
|
1172
|
+
// a second caller had since doubled it).
|
|
1173
|
+
//
|
|
1174
|
+
// Placed after the vocabulary check so an unknown event is not an
|
|
1175
|
+
// opportunity, and before the manifest load so a missing manifest still is.
|
|
1176
|
+
recordOpportunity(args.event, args.platform);
|
|
1177
|
+
recordCapture(args.event, args.platform);
|
|
1178
|
+
|
|
1147
1179
|
const manifest_path = args.manifest;
|
|
1148
1180
|
if (!fs.existsSync(manifest_path)) {
|
|
1149
1181
|
process.stderr.write(`dispatch_hook: manifest missing at ${manifest_path}\n`);
|