@event4u/agent-config 16.2.0 → 16.4.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 +337 -234
- package/README.md +15 -13
- package/agents/templates/.ai-council.yml.example +26 -8
- package/dist/agent-src/commands/analyze/inbox.md +11 -8
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/bug/investigate.md +1 -1
- package/dist/agent-src/commands/commit/in-chunks.md +40 -31
- package/dist/agent-src/commands/commit.md +72 -33
- package/dist/agent-src/commands/condense.md +2 -8
- package/dist/agent-src/commands/council/debate.md +11 -7
- package/dist/agent-src/commands/council/default.md +10 -9
- package/dist/agent-src/commands/council.md +1 -1
- package/dist/agent-src/commands/estimate-ticket.md +1 -1
- package/dist/agent-src/commands/feature/explore.md +3 -3
- package/dist/agent-src/commands/feature/plan.md +2 -2
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +18 -4
- package/dist/agent-src/commands/fix/commit-messages.md +48 -23
- package/dist/agent-src/commands/fix/pr-comments.md +3 -6
- package/dist/agent-src/commands/implement-ticket.md +4 -4
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/memory/add.md +4 -16
- package/dist/agent-src/commands/memory/load.md +5 -6
- package/dist/agent-src/commands/memory/promote.md +3 -16
- package/dist/agent-src/commands/mission/upgrade.md +3 -2
- package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
- package/dist/agent-src/commands/optimize/deep.md +4 -2
- package/dist/agent-src/commands/optimize/rtk.md +4 -26
- package/dist/agent-src/commands/pr/create/description-only.md +18 -15
- package/dist/agent-src/commands/pr/create.md +42 -34
- package/dist/agent-src/commands/pr/merge.md +136 -9
- package/dist/agent-src/commands/prepare-for-review.md +13 -11
- package/dist/agent-src/commands/project/analyze.md +7 -35
- package/dist/agent-src/commands/refine-ticket.md +1 -1
- package/dist/agent-src/commands/review/changes.md +14 -19
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/next.md +10 -1
- package/dist/agent-src/commands/roadmap/process-full.md +56 -42
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +411 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/worktree/create.md +7 -3
- package/dist/agent-src/commands/worktree/verify.md +2 -1
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +5 -3
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
- package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +7 -7
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
- package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
- package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
- package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +99 -54
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
- package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
- package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +95 -7
- package/dist/agent-src/contexts/subagent-configuration.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
- package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
- package/dist/agent-src/guidelines/php/git.md +15 -2
- package/dist/agent-src/rules/active-remediation.md +1 -2
- package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
- package/dist/agent-src/rules/architecture.md +0 -1
- package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
- package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
- package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -1
- package/dist/agent-src/rules/brand-consistency.md +0 -1
- package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
- package/dist/agent-src/rules/broken-access-control.md +1 -1
- package/dist/agent-src/rules/cli-output-handling.md +0 -1
- package/dist/agent-src/rules/code-comment-discipline.md +0 -1
- package/dist/agent-src/rules/code-provenance.md +0 -1
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -1
- package/dist/agent-src/rules/commit-conventions.md +1 -2
- package/dist/agent-src/rules/communication-through-line.md +1 -2
- package/dist/agent-src/rules/content-quoting-floor.md +1 -2
- package/dist/agent-src/rules/context-hygiene.md +6 -6
- package/dist/agent-src/rules/copilot-routing.md +1 -2
- package/dist/agent-src/rules/council-availability.md +4 -4
- package/dist/agent-src/rules/cross-source-consistency.md +4 -6
- package/dist/agent-src/rules/decision-revisit-gate.md +17 -35
- package/dist/agent-src/rules/delegation-policy.md +2 -3
- package/dist/agent-src/rules/design-fidelity.md +12 -16
- package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
- package/dist/agent-src/rules/devcontainer-routing.md +1 -2
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
- package/dist/agent-src/rules/docker-commands.md +0 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +1 -1
- package/dist/agent-src/rules/domain-safety-retention.md +1 -1
- package/dist/agent-src/rules/downstream-changes.md +0 -1
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -1
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
- package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +2 -2
- package/dist/agent-src/rules/finance-safety-floor.md +1 -1
- package/dist/agent-src/rules/fix-what-you-see.md +6 -32
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
- package/dist/agent-src/rules/git-history-discipline.md +2 -2
- package/dist/agent-src/rules/guidelines.md +0 -1
- package/dist/agent-src/rules/history-discipline.md +0 -1
- package/dist/agent-src/rules/icon-consistency.md +0 -1
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -1
- package/dist/agent-src/rules/improve-before-implement.md +0 -1
- package/dist/agent-src/rules/invite-challenge.md +0 -1
- package/dist/agent-src/rules/laravel-routing.md +1 -2
- package/dist/agent-src/rules/laravel-translations.md +0 -1
- package/dist/agent-src/rules/legal-safety-floor.md +3 -3
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -1
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -1
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
- package/dist/agent-src/rules/media-governance-routing.md +13 -17
- package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
- package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
- package/dist/agent-src/rules/missing-tool-handling.md +0 -1
- package/dist/agent-src/rules/model-recommendation.md +0 -1
- package/dist/agent-src/rules/neighbour-precedence.md +64 -0
- package/dist/agent-src/rules/no-attribution-footers.md +0 -1
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
- package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
- package/dist/agent-src/rules/no-roadmap-references.md +0 -1
- package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
- package/dist/agent-src/rules/onboarding-gate.md +0 -1
- package/dist/agent-src/rules/output-discipline.md +0 -1
- package/dist/agent-src/rules/package-ci-checks.md +0 -1
- package/dist/agent-src/rules/persona-governance.md +4 -5
- package/dist/agent-src/rules/php-coding.md +0 -1
- package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
- package/dist/agent-src/rules/preservation-guard.md +0 -1
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -4
- package/dist/agent-src/rules/question-not-instruction.md +1 -1
- package/dist/agent-src/rules/reviewer-awareness.md +0 -1
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +4 -7
- package/dist/agent-src/rules/role-mode-adherence.md +0 -1
- package/dist/agent-src/rules/rule-type-governance.md +0 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -1
- package/dist/agent-src/rules/scale-discipline.md +0 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -3
- package/dist/agent-src/rules/self-repair-loop.md +0 -1
- package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
- package/dist/agent-src/rules/session-canary.md +7 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +6 -6
- package/dist/agent-src/rules/size-enforcement.md +0 -1
- package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
- package/dist/agent-src/rules/skill-quality.md +0 -1
- package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
- package/dist/agent-src/rules/source-confidentiality.md +1 -1
- package/dist/agent-src/rules/source-discovery-gate.md +0 -1
- package/dist/agent-src/rules/source-of-truth.md +0 -1
- package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
- package/dist/agent-src/rules/symfony-routing.md +1 -2
- package/dist/agent-src/rules/think-before-action.md +0 -1
- package/dist/agent-src/rules/token-budget-discipline.md +12 -46
- package/dist/agent-src/rules/token-efficiency.md +0 -1
- package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
- package/dist/agent-src/rules/tool-safety.md +1 -1
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -1
- package/dist/agent-src/rules/upstream-proposal.md +0 -1
- package/dist/agent-src/rules/user-interaction.md +0 -1
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -1
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/gate_budget.ts +47 -23
- package/dist/agent-src/scripts/gate_execute.ts +12 -4
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
- package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
- package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
- package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
- package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
- package/dist/agent-src/skills/database/data/manifest.json +2 -2
- package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
- package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
- package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
- package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +5 -3
- package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +4 -2
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
- package/dist/agent-src/templates/AGENTS.md +1 -1
- package/dist/agent-src/templates/agent-settings.md +46 -129
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
- package/dist/agent-src/templates/command.md +2 -2
- package/dist/agent-src/templates/roadmaps.md +6 -1
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/skill.md +1 -1
- package/dist/cli/registry.js +2 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +207 -120
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-5GPULQBE.js} +2797 -338
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-6SRJTYJS.js} +42 -176
- package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
- package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-AED2VQGM.js} +1245 -249
- package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
- package/dist/cli-delegate/chunk-F3QDG2GT.js +2569 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-G5VVIZRC.js} +3 -3
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-H76PHZBI.js} +149 -61
- package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-KXXWJTDO.js} +6 -11
- package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-MDPPKQCQ.js} +58 -9
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-MSUL5NYP.js} +5 -5
- package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-PWX7CKMD.js} +4 -4
- package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-T7XSJSUQ.js} +1144 -589
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/chunk-WQWXGIWB.js +1779 -0
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-XQTPXKFA.js} +1 -1
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +223 -43
- package/dist/cli-delegate/cmd_brand_status.js +3 -2
- package/dist/cli-delegate/cmd_conformance.js +1252 -249
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +19 -9
- package/dist/cli-delegate/cmd_doctor_neighbours.js +30 -0
- package/dist/cli-delegate/cmd_explain.js +45 -21
- package/dist/cli-delegate/cmd_export.js +13 -10
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_git_convention.js +1851 -0
- package/dist/cli-delegate/cmd_handoff.js +44 -22
- package/dist/cli-delegate/cmd_mcp_available.js +3 -2
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +3 -3
- package/dist/cli-delegate/cmd_packs_active.js +5 -4
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +14 -11
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +10 -8
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +10 -7
- package/dist/cli-delegate/cmd_settings_check.js +54 -7
- package/dist/cli-delegate/cmd_settings_get.js +18 -8
- package/dist/cli-delegate/cmd_settings_migrate.js +13 -10
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +14 -11
- package/dist/cli-delegate/cmd_uninstall.js +15 -12
- package/dist/cli-delegate/cmd_update.js +7 -7
- package/dist/cli-delegate/cmd_upgrade.js +9 -8
- package/dist/cli-delegate/cmd_validate.js +15 -12
- package/dist/cli-delegate/cmd_versions.js +5 -5
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_budget.js +1 -1
- package/dist/cli-delegate/gate_execute.js +3 -3
- package/dist/cli-delegate/roadmap_gates.js +6 -6
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +232 -141
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +26 -9
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +7 -4
- package/dist/hooks/dispatch.js +5655 -6623
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2336 -1249
- package/dist/install/installThinLayer.js +289 -0
- package/dist/install/installedRuleLinks.js +262 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
- package/dist/mcp/registry-manifest.json +5 -5
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +36504 -30986
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +26 -120
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/compile_time_toggles.js +12 -21
- package/dist/scripts/_lib/git_convention.js +232 -0
- package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
- package/dist/scripts/_lib/installed_layer.js +704 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/package_root.js +68 -0
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/settings_removed_keys.js +168 -0
- package/dist/scripts/_lib/thin_rules.js +535 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/app.js +2 -1
- package/dist/server/gitKeysGate.js +105 -0
- package/dist/server/routes/settings.js +67 -8
- package/dist/server/routes/wizard.js +4 -0
- package/dist/server/schemas/settings.js +29 -81
- package/dist/shared/skillRanking.js +103 -16
- package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +72 -1
- package/docs/contracts/settings-classes.md +39 -67
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/docs/guidelines/agent-infra/layered-settings.md +13 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
- package/docs/guidelines/php/git.md +15 -2
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/gate_budget.ts +47 -23
- package/src/agent-src/scripts/gate_execute.ts +12 -4
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/AGENTS.md +1 -1
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +141 -334
- package/src/config/agents-paths.yml +16 -0
- package/src/config/assurance-capability-registry.json +7 -3
- package/src/config/ci-local-parity.yml +3 -0
- package/src/config/continuity-surface.json +10 -3
- package/src/config/discovery/packs.yml +17 -1
- package/src/config/evaluator-budgets.json +23 -10
- package/src/config/gate-coverage.yml +138 -3
- package/src/config/gate-violation-baselines.json +64 -16
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/release-gate-locality.yml +2 -1
- package/src/config/routing-coverage-seed.json +67 -4
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +105 -0
- package/src/config/rule-obligations.json +833 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +378 -0
- package/src/install/installedRuleLinks.ts +308 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
- package/src/scripts/_cli/cmd_conformance.ts +13 -2
- package/src/scripts/_cli/cmd_doctor.ts +33 -81
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +426 -0
- package/src/scripts/_cli/cmd_explain.ts +72 -14
- package/src/scripts/_cli/cmd_git_convention.ts +637 -0
- package/src/scripts/_cli/cmd_settings_check.ts +66 -8
- package/src/scripts/_cli/cmd_settings_get.ts +18 -3
- package/src/scripts/_cli/doctor_execution.ts +72 -1
- package/src/scripts/_dispatch.bash +53 -4
- package/src/scripts/_lib/agent_settings.ts +26 -124
- package/src/scripts/_lib/blocked_by_marker.ts +1 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/compile_time_toggles.ts +12 -21
- package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/git_base_ref.ts +92 -0
- package/src/scripts/_lib/git_convention.ts +291 -0
- package/src/scripts/_lib/git_convention_carrier.ts +389 -0
- package/src/scripts/_lib/git_convention_grammar.ts +246 -0
- package/src/scripts/_lib/git_convention_measure.ts +344 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +106 -0
- package/src/scripts/_lib/graph_feeder_record.ts +437 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +963 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/knowledge_global.ts +14 -1
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/module_reach.ts +456 -0
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +187 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/ratification_artifact.ts +220 -1
- package/src/scripts/_lib/ratification_subject.ts +92 -0
- package/src/scripts/_lib/release_findings_ingest.ts +15 -7
- package/src/scripts/_lib/release_highlights.ts +5 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/rule_obligations.ts +205 -0
- package/src/scripts/_lib/self_repair.ts +1 -1
- package/src/scripts/_lib/settings_removed_keys.ts +173 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/test_red_state.ts +5 -0
- package/src/scripts/_lib/thin_rules.ts +620 -0
- package/src/scripts/_lib/touched_file_quality.ts +570 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/_lib/worker_budget.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +16 -1
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +8 -8
- package/src/scripts/ai_council/modification_review.ts +100 -0
- package/src/scripts/ai_council/modification_review_questions.ts +90 -0
- package/src/scripts/ai_council/orchestrator.ts +5 -5
- package/src/scripts/ai_council/spend_gate.ts +18 -7
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/config.ts +11 -16
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/audit_user_type_axis.ts +20 -8
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_ab_clone.ts +1 -2
- package/src/scripts/bench_concern_spawn_path.ts +129 -0
- package/src/scripts/bench_graph_feeder_latency.ts +584 -0
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_agent_artifact_location.ts +36 -0
- package/src/scripts/check_branch_freshness.ts +147 -24
- package/src/scripts/check_enforcement_coverage.ts +130 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_evaluator_budgets.ts +4 -0
- package/src/scripts/check_finding_dispositions.ts +196 -21
- package/src/scripts/check_gate_coverage.ts +4 -3
- package/src/scripts/check_gate_reachability.ts +48 -1
- package/src/scripts/check_generator_sync.ts +48 -0
- package/src/scripts/check_hook_bundle_composition.ts +477 -0
- package/src/scripts/check_kernel_edit_ratified.ts +132 -14
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_pack_size.ts +1 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_manifest_content.ts +189 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +129 -13
- package/src/scripts/check_suppression_hygiene.ts +2 -5
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +42 -5
- package/src/scripts/classify_merge_risk.ts +320 -0
- package/src/scripts/closure_scan.ts +91 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/command_suggester/settings.ts +8 -108
- package/src/scripts/command_suggester/types.ts +4 -5
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/consumer_matrix.ts +102 -0
- package/src/scripts/context_hygiene_hook.ts +13 -23
- package/src/scripts/cost/preflight.mjs +12 -1
- package/src/scripts/council_cli.ts +7 -7
- package/src/scripts/dispatch_r2_reviewer.ts +24 -11
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/explain_run.ts +8 -13
- package/src/scripts/generate_git_convention_grammar.ts +127 -0
- package/src/scripts/generate_host_cost_table.ts +21 -4
- package/src/scripts/handoff_context_hook.ts +86 -37
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +175 -15
- package/src/scripts/hooks/block_config_weakening.ts +115 -7
- package/src/scripts/hooks/block_plumbing_writes.ts +37 -5
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/evidence_independence.ts +12 -4
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/push_settle_hook.ts +4 -3
- package/src/scripts/hooks/rule_inject_hook.ts +795 -60
- package/src/scripts/hooks/state_io.ts +8 -4
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +24 -7
- package/src/scripts/hooks/turn_end_gate_hook.ts +85 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install-hooks.sh +42 -14
- package/src/scripts/install.ts +78 -215
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_blocker_citations.ts +198 -0
- package/src/scripts/lint_evidence_artifacts.ts +9 -0
- package/src/scripts/lint_hook_concern_budget.ts +10 -21
- package/src/scripts/lint_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +465 -29
- package/src/scripts/lint_roadmap_blockers.ts +282 -29
- package/src/scripts/lint_roadmap_complexity.ts +4 -2
- package/src/scripts/lint_rule_law_section.ts +647 -0
- package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
- package/src/scripts/lint_settings_classes.ts +1 -1
- package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
- package/src/scripts/lint_workflow_security.ts +173 -6
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +221 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +55 -8
- package/src/scripts/onboarding_gate_hook.ts +7 -6
- package/src/scripts/print_required_checks.ts +15 -3
- package/src/scripts/probe_host_compliance.ts +33 -5
- package/src/scripts/probe_turnaround.ts +183 -3
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/ratification_header.ts +77 -0
- package/src/scripts/refusal_envelope.ts +138 -0
- package/src/scripts/release_publication.ts +29 -3
- package/src/scripts/report_dispatch_import_closure.ts +76 -0
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +274 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_module_reach.ts +212 -0
- package/src/scripts/report_obligation_mechanism.ts +228 -0
- package/src/scripts/report_parked_blockers.ts +222 -0
- package/src/scripts/report_required_checks_drift.ts +196 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +543 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/routing_doctor.ts +2 -2
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/agent-settings.schema.json +17 -31
- package/src/scripts/schemas/command.schema.json +1 -1
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +1 -1
- package/src/scripts/self_review_gate.ts +101 -9
- package/src/scripts/skill_tools/score_skill_relevance.ts +314 -40
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/sync_pr_branch.ts +403 -132
- package/src/scripts/trigger_eval_grandfather.json +0 -21
- package/src/server/schemas/settings.ts +42 -176
- package/src/shared/skillRanking.ts +169 -14
- package/dist/cli-delegate/chunk-5R7HOLAF.js +0 -99
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/src/scripts/_lib/config_chain.ts +0 -477
- package/src/scripts/_lib/conformance_report.ts +0 -403
- package/src/scripts/_lib/eval_discrimination.ts +0 -95
- package/src/scripts/_lib/evaluator_promotion.ts +0 -225
- package/src/scripts/_lib/file_slicer.ts +0 -117
- package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
- package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
- package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
- package/src/scripts/_lib/role_split.ts +0 -338
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* classify_merge_risk — ADR-282's danger gate in front of an authorized
|
|
4
|
+
* auto-merge.
|
|
5
|
+
*
|
|
6
|
+
* Says `routine` or `needs-council` for a diff, plus the triggers that fired.
|
|
7
|
+
* `routine` merges on the owner's auto-merge instruction with no review;
|
|
8
|
+
* `needs-council` sends the diff to the AI council first. The classifier is
|
|
9
|
+
* advisory to that flow and grants nothing on its own.
|
|
10
|
+
*
|
|
11
|
+
* Every trigger is lifted from a rule that already exists, never invented here:
|
|
12
|
+
*
|
|
13
|
+
* - `non-destructive-by-default` Hard-Floor rows: bulk deletion (a removed
|
|
14
|
+
* directory, or DELETION_THRESHOLD deleted files), infrastructure config,
|
|
15
|
+
* production data and migrations, deploy and release paths.
|
|
16
|
+
* - `security-sensitive-stop` surfaces: auth, authz, tenancy, billing,
|
|
17
|
+
* secrets, uploads, webhooks, route files (public endpoints).
|
|
18
|
+
* - The ratification surfaces, read through `check_kernel_edit_ratified`'s own
|
|
19
|
+
* `classifyPaths` — a second list would drift from the first.
|
|
20
|
+
* - Any CI workflow: `process-full` makes a disabled required check the thing
|
|
21
|
+
* delivery-ready must refuse, and a green rollup on a weakened workflow is
|
|
22
|
+
* exactly what a no-review merge would trust.
|
|
23
|
+
* - Its own surface — this file and the two commands that call it — for the
|
|
24
|
+
* reason the ratification gate watches itself: a routine-class PR must not
|
|
25
|
+
* be able to loosen the gate that classed it.
|
|
26
|
+
*
|
|
27
|
+
* Prose files (`.md`, `.mdx`, `.txt`, `.rst`) are exempt from the security,
|
|
28
|
+
* infra and migration token checks: a skill ABOUT secrets is not a secret
|
|
29
|
+
* surface. They stay subject to deletion, governance and self-surface checks.
|
|
30
|
+
*
|
|
31
|
+
* Fails closed: a diff that cannot be read is `needs-council`, never `routine`,
|
|
32
|
+
* and never an internal-error exit a caller might read as "nothing found".
|
|
33
|
+
*
|
|
34
|
+
* Inputs (one of):
|
|
35
|
+
* <pr-number> PR mode: base and head read via `gh`, head fetched
|
|
36
|
+
* --range BASE..HEAD range mode (`...` also accepted)
|
|
37
|
+
* Options:
|
|
38
|
+
* --root DIR repository to read (default: cwd)
|
|
39
|
+
* --json one JSON object instead of text
|
|
40
|
+
*
|
|
41
|
+
* Exit codes: 0 = routine · 1 = needs-council (including fail-closed).
|
|
42
|
+
* The LAST output line is the verdict.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import { spawnSync } from 'node:child_process';
|
|
46
|
+
import * as path from 'node:path';
|
|
47
|
+
import { pathToFileURL } from 'node:url';
|
|
48
|
+
|
|
49
|
+
import { classifyPaths, requiresRatification } from './check_kernel_edit_ratified.js';
|
|
50
|
+
|
|
51
|
+
export const DELETION_THRESHOLD = 5;
|
|
52
|
+
|
|
53
|
+
export interface ChangeEntry {
|
|
54
|
+
status: string;
|
|
55
|
+
path: string;
|
|
56
|
+
oldPath?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface Trigger {
|
|
60
|
+
id: string;
|
|
61
|
+
rule: string;
|
|
62
|
+
paths: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface Classification {
|
|
66
|
+
verdict: 'routine' | 'needs-council';
|
|
67
|
+
triggers: Trigger[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface ClassifyOptions {
|
|
71
|
+
/** Does `dir` still exist in the head tree? Decides a removed directory. */
|
|
72
|
+
dirExistsInHead: (dir: string) => boolean;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const PROSE_EXT = new Set(['.md', '.mdx', '.txt', '.rst']);
|
|
76
|
+
|
|
77
|
+
const SECURITY_TOKENS = new Set([
|
|
78
|
+
'auth', 'authn', 'authz', 'authenticate', 'authentication', 'authorization', 'authorize',
|
|
79
|
+
'login', 'logout', 'oauth', 'sso', 'saml', 'mfa', '2fa', 'password', 'passwords', 'passwd', 'jwt',
|
|
80
|
+
'permission', 'permissions', 'rbac', 'acl', 'policy', 'policies',
|
|
81
|
+
'tenant', 'tenants', 'tenancy', 'multitenancy',
|
|
82
|
+
'billing', 'payment', 'payments', 'invoice', 'invoices', 'subscription', 'subscriptions',
|
|
83
|
+
'refund', 'refunds', 'charge', 'charges',
|
|
84
|
+
'secret', 'secrets', 'credential', 'credentials', 'vault', 'kms', 'env',
|
|
85
|
+
'upload', 'uploads', 'webhook', 'webhooks', 'routes',
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const INFRA_SEGMENTS = new Set([
|
|
89
|
+
'terraform', 'terragrunt', 'pulumi', 'k8s', 'kubernetes', 'helm', 'charts', 'ansible',
|
|
90
|
+
'cloudformation', 'cdk', 'infra', 'infrastructure',
|
|
91
|
+
]);
|
|
92
|
+
const INFRA_EXT = new Set(['.tf', '.tfvars', '.hcl']);
|
|
93
|
+
const INFRA_BASENAME_RE = /^(?:Pulumi(?:\.[\w-]+)?\.ya?ml|Chart\.ya?ml|kustomization\.ya?ml|serverless\.ya?ml)$/;
|
|
94
|
+
|
|
95
|
+
const PROD_TOKENS = new Set(['prod', 'production']);
|
|
96
|
+
const MIGRATION_SEGMENTS = new Set(['migrations', 'migration', 'migrate']);
|
|
97
|
+
const DEPLOY_TOKENS = new Set(['deploy', 'deployment', 'deployments', 'release', 'releases', 'publish']);
|
|
98
|
+
|
|
99
|
+
const SELF_SURFACE_RE =
|
|
100
|
+
/(?:^|\/)(?:scripts\/classify_merge_risk\.ts|domains\/git\/pr\/merge\/command\.md|domains\/product-basic\/roadmap\/process-full\/command\.md)$|^docs\/decisions\/ADR-282-[^/]+\.md$/;
|
|
101
|
+
|
|
102
|
+
/** Lower-cased word tokens of a path: split on separators and camelCase. */
|
|
103
|
+
function tokens(p: string): string[] {
|
|
104
|
+
return p
|
|
105
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
106
|
+
.toLowerCase()
|
|
107
|
+
.split(/[\/._\-\s]+/)
|
|
108
|
+
.filter((t) => t !== '');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function segments(p: string): string[] {
|
|
112
|
+
return p.toLowerCase().split('/');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isProse(p: string): boolean {
|
|
116
|
+
return PROSE_EXT.has(path.posix.extname(p).toLowerCase());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function isSecurity(p: string): boolean {
|
|
120
|
+
if (isProse(p)) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
const base = path.posix.basename(p);
|
|
124
|
+
if (base === '.env' || base.startsWith('.env.')) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return tokens(p).some((t) => SECURITY_TOKENS.has(t));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isInfra(p: string): boolean {
|
|
131
|
+
if (INFRA_EXT.has(path.posix.extname(p).toLowerCase()) || INFRA_BASENAME_RE.test(path.posix.basename(p))) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return !isProse(p) && segments(p).slice(0, -1).some((s) => INFRA_SEGMENTS.has(s));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isProdOrMigration(p: string): boolean {
|
|
138
|
+
if (path.posix.extname(p).toLowerCase() === '.sql') {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
if (isProse(p)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return segments(p).some((s) => MIGRATION_SEGMENTS.has(s)) || tokens(p).some((t) => PROD_TOKENS.has(t));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function isDeployOrRelease(p: string): boolean {
|
|
148
|
+
return !isProse(p) && tokens(p).some((t) => DEPLOY_TOKENS.has(t));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function isWorkflow(p: string): boolean {
|
|
152
|
+
return p.startsWith('.github/workflows/');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Every path a change touches — both sides of a rename or copy. */
|
|
156
|
+
function touched(entries: readonly ChangeEntry[]): string[] {
|
|
157
|
+
const out = new Set<string>();
|
|
158
|
+
for (const e of entries) {
|
|
159
|
+
out.add(e.path);
|
|
160
|
+
if (e.oldPath !== undefined) {
|
|
161
|
+
out.add(e.oldPath);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return [...out];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function classifyChanges(entries: readonly ChangeEntry[], opts: ClassifyOptions): Classification {
|
|
168
|
+
const triggers: Trigger[] = [];
|
|
169
|
+
const add = (id: string, rule: string, paths: string[]): void => {
|
|
170
|
+
if (paths.length > 0) {
|
|
171
|
+
triggers.push({ id, rule, paths: [...paths].sort() });
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const all = touched(entries);
|
|
175
|
+
const deleted = entries.filter((e) => e.status === 'D').map((e) => e.path);
|
|
176
|
+
|
|
177
|
+
if (deleted.length >= DELETION_THRESHOLD) {
|
|
178
|
+
add('bulk-deletion', `non-destructive-by-default — ${deleted.length} deleted files (≥ ${DELETION_THRESHOLD})`, deleted);
|
|
179
|
+
}
|
|
180
|
+
const goneDirs = [...new Set(deleted.map((p) => path.posix.dirname(p)).filter((d) => d !== '.'))].filter(
|
|
181
|
+
(d) => !opts.dirExistsInHead(d),
|
|
182
|
+
);
|
|
183
|
+
add(
|
|
184
|
+
'removed-directory',
|
|
185
|
+
'non-destructive-by-default — a directory no longer exists in the head',
|
|
186
|
+
deleted.filter((p) => goneDirs.includes(path.posix.dirname(p))),
|
|
187
|
+
);
|
|
188
|
+
add('infra-config', 'non-destructive-by-default — Terraform / Pulumi / k8s / Ansible / cloud config', all.filter(isInfra));
|
|
189
|
+
add('prod-data-or-migration', 'non-destructive-by-default — production data or a migration', all.filter(isProdOrMigration));
|
|
190
|
+
add('deploy-or-release', 'non-destructive-by-default — deploy or release path', all.filter(isDeployOrRelease));
|
|
191
|
+
add('ci-workflow', 'process-full — a disabled required check cannot reach delivery-ready', all.filter(isWorkflow));
|
|
192
|
+
add('security-surface', 'security-sensitive-stop — auth, authz, tenancy, billing, secrets, uploads, webhooks, routes', all.filter(isSecurity));
|
|
193
|
+
|
|
194
|
+
const gated = classifyPaths(all);
|
|
195
|
+
if (requiresRatification(gated)) {
|
|
196
|
+
const gatedPaths = [...gated.kernelRules, ...gated.governanceHooks, ...gated.plumbing];
|
|
197
|
+
add(
|
|
198
|
+
'governance-surface',
|
|
199
|
+
'check_kernel_edit_ratified — kernel rule, governance hook, hook plumbing or the ratification mechanism',
|
|
200
|
+
gatedPaths.length > 0 ? gatedPaths : all.filter((p) => classifyPaths([p]).self),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
add('merge-authority-surface', 'ADR-282 — the danger gate and the commands that call it', all.filter((p) => SELF_SURFACE_RE.test(p)));
|
|
204
|
+
|
|
205
|
+
return { verdict: triggers.length > 0 ? 'needs-council' : 'routine', triggers };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Parse `git diff --name-status` output. Throws on a line it cannot read. */
|
|
209
|
+
export function parseNameStatus(text: string): ChangeEntry[] {
|
|
210
|
+
const out: ChangeEntry[] = [];
|
|
211
|
+
for (const line of text.split('\n')) {
|
|
212
|
+
if (line.trim() === '') {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const parts = line.split('\t');
|
|
216
|
+
const status = (parts[0] ?? '').charAt(0);
|
|
217
|
+
if (parts.length < 2 || !/^[AMDRCTU]$/.test(status)) {
|
|
218
|
+
throw new Error(`unreadable name-status line: ${JSON.stringify(line)}`);
|
|
219
|
+
}
|
|
220
|
+
if ((status === 'R' || status === 'C') && parts.length >= 3) {
|
|
221
|
+
out.push({ status, oldPath: parts[1] ?? '', path: parts[2] ?? '' });
|
|
222
|
+
} else {
|
|
223
|
+
out.push({ status, path: parts[1] ?? '' });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function git(root: string, args: string[]): { ok: boolean; out: string } {
|
|
230
|
+
const r = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
231
|
+
return { ok: r.status === 0, out: r.stdout ?? '' };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
interface Resolved {
|
|
235
|
+
base: string;
|
|
236
|
+
head: string;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function resolvePr(root: string, pr: string): Resolved | null {
|
|
240
|
+
const v = spawnSync('gh', ['pr', 'view', pr, '--json', 'baseRefName,headRefOid'], { cwd: root, encoding: 'utf8' });
|
|
241
|
+
if (v.status !== 0) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
const meta = JSON.parse(v.stdout) as { baseRefName?: string; headRefOid?: string };
|
|
245
|
+
if (meta.baseRefName === undefined || meta.headRefOid === undefined) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
git(root, ['fetch', '-q', 'origin', meta.baseRefName, `pull/${pr}/head`]);
|
|
249
|
+
return { base: `origin/${meta.baseRefName}`, head: meta.headRefOid };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function resolveRange(range: string): Resolved | null {
|
|
253
|
+
const m = /^(.+?)\.\.\.?(.+)$/.exec(range);
|
|
254
|
+
return m === null ? null : { base: m[1] ?? '', head: m[2] ?? '' };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function failClosed(reason: string): Classification {
|
|
258
|
+
return { verdict: 'needs-council', triggers: [{ id: 'diff-unreadable', rule: 'fail closed — ADR-282', paths: [reason] }] };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function classifyTarget(root: string, target: { pr?: string | undefined; range?: string | undefined }): Classification {
|
|
262
|
+
const resolved = target.pr !== undefined ? resolvePr(root, target.pr) : resolveRange(target.range ?? '');
|
|
263
|
+
if (resolved === null) {
|
|
264
|
+
return failClosed('could not resolve base and head');
|
|
265
|
+
}
|
|
266
|
+
const diff = git(root, ['diff', '--name-status', '-M', `${resolved.base}...${resolved.head}`]);
|
|
267
|
+
if (!diff.ok) {
|
|
268
|
+
return failClosed(`git diff ${resolved.base}...${resolved.head} failed`);
|
|
269
|
+
}
|
|
270
|
+
let entries: ChangeEntry[];
|
|
271
|
+
try {
|
|
272
|
+
entries = parseNameStatus(diff.out);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
return failClosed((e as Error).message);
|
|
275
|
+
}
|
|
276
|
+
return classifyChanges(entries, {
|
|
277
|
+
dirExistsInHead: (dir) => git(root, ['cat-file', '-e', `${resolved.head}:${dir}`]).ok,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function main(argv: readonly string[] = process.argv.slice(2), write: (l: string) => void = (l) => process.stdout.write(`${l}\n`)): number {
|
|
282
|
+
let root = process.cwd();
|
|
283
|
+
let range: string | undefined;
|
|
284
|
+
let pr: string | undefined;
|
|
285
|
+
let json = false;
|
|
286
|
+
for (let i = 0; i < argv.length; i++) {
|
|
287
|
+
const a = argv[i] ?? '';
|
|
288
|
+
if (a === '--root') {
|
|
289
|
+
root = argv[++i] ?? root;
|
|
290
|
+
} else if (a === '--range') {
|
|
291
|
+
range = argv[++i];
|
|
292
|
+
} else if (a === '--json') {
|
|
293
|
+
json = true;
|
|
294
|
+
} else if (/^\d+$/.test(a)) {
|
|
295
|
+
pr = a;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const result =
|
|
299
|
+
pr === undefined && range === undefined ? failClosed('no PR number and no --range given') : classifyTarget(root, { pr, range });
|
|
300
|
+
if (json) {
|
|
301
|
+
write(JSON.stringify(result));
|
|
302
|
+
} else {
|
|
303
|
+
for (const t of result.triggers) {
|
|
304
|
+
write(`trigger ${t.id} — ${t.rule}`);
|
|
305
|
+
for (const p of t.paths) {
|
|
306
|
+
write(` ${p}`);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
write(
|
|
310
|
+
result.verdict === 'routine'
|
|
311
|
+
? 'verdict: routine'
|
|
312
|
+
: `verdict: needs-council (${result.triggers.length} trigger(s): ${result.triggers.map((t) => t.id).join(', ')})`,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return result.verdict === 'routine' ? 0 : 1;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? '').href) {
|
|
319
|
+
process.exit(main());
|
|
320
|
+
}
|
|
@@ -130,7 +130,12 @@ export const NON_BLOCKING_KINDS: ReadonlySet<Kind> = new Set<Kind>(['unfalsifiab
|
|
|
130
130
|
* on the CONTENT a step asserts. Anything whose exit code already tracks the
|
|
131
131
|
* claim — `grep` (1 on no match), a linter, a test runner — is absent on
|
|
132
132
|
* purpose: including it would turn this listing into a census of every verify
|
|
133
|
-
* line in the tree, which is step 2.2's instrument, not this one.
|
|
133
|
+
* line in the tree, which is step 2.2's instrument, not this one. One case
|
|
134
|
+
* reads titles and runs nothing: a name-filtered test run
|
|
135
|
+
* (`vitest run <target> -t <name>`) whose target exists carries its own
|
|
136
|
+
* failure mode a plain exit-code read cannot see — `-t` with no matching
|
|
137
|
+
* title skips every test and still exits 0 — so that one shape is read for
|
|
138
|
+
* content, never executed, in `_nameFilterHasNoMatch` below.
|
|
134
139
|
*/
|
|
135
140
|
const FIXED_OUTPUT_HEADS: ReadonlySet<string> = new Set(['echo', 'true', 'printf', 'cat', 'ls', 'pwd', 'date']);
|
|
136
141
|
|
|
@@ -149,6 +154,87 @@ const FIXED_OUTPUT_HEADS: ReadonlySet<string> = new Set(['echo', 'true', 'printf
|
|
|
149
154
|
* remainder as clean, which is the same mistake as reporting a share off a
|
|
150
155
|
* corpus nobody scanned.
|
|
151
156
|
*/
|
|
157
|
+
// `vitest run <target> -t <name>` (optionally `npx`-prefixed); `<name>` may
|
|
158
|
+
// be bare, single-quoted or double-quoted. The target is captured
|
|
159
|
+
// non-greedily up to the first whitespace or quote.
|
|
160
|
+
const VITEST_NAME_FILTER_RE = /(?:^|\s)vitest\s+run\s+(\S+)\s+-t\s+(?:'([^']+)'|"([^"]+)"|(\S+))/;
|
|
161
|
+
|
|
162
|
+
// `describe(`, `it(`, `test(`, and their `.only`/`.skip`/`.each`/`.todo`
|
|
163
|
+
// modifiers, each with a quoted first argument — the title vitest matches
|
|
164
|
+
// `-t` against (concatenated with its ancestor `describe` titles at
|
|
165
|
+
// run time; this reads each title string standalone, which is sufficient to
|
|
166
|
+
// prove a filter CAN match something — the question this function asks).
|
|
167
|
+
const TEST_TITLE_RE = /\b(?:describe|it|test)(?:\.\w+)?\s*\(\s*(['"`])((?:(?!\1).)*)\1/g;
|
|
168
|
+
|
|
169
|
+
function _collectTestFiles(target: string): string[] {
|
|
170
|
+
let stat: fs.Stats;
|
|
171
|
+
try {
|
|
172
|
+
stat = fs.statSync(target);
|
|
173
|
+
} catch {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
if (stat.isFile()) return [target];
|
|
177
|
+
if (!stat.isDirectory()) return [];
|
|
178
|
+
const out: string[] = [];
|
|
179
|
+
let entries: string[];
|
|
180
|
+
try {
|
|
181
|
+
entries = fs.readdirSync(target, { recursive: true }) as string[];
|
|
182
|
+
} catch {
|
|
183
|
+
return [];
|
|
184
|
+
}
|
|
185
|
+
for (const rel of entries) {
|
|
186
|
+
if (!/\.(?:test|spec)\.tsx?$/.test(rel)) continue;
|
|
187
|
+
out.push(path.join(target, rel));
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function _extractTitles(file: string): string[] {
|
|
193
|
+
let text: string;
|
|
194
|
+
try {
|
|
195
|
+
text = fs.readFileSync(file, 'utf-8');
|
|
196
|
+
} catch {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
const titles: string[] = [];
|
|
200
|
+
const re = new RegExp(TEST_TITLE_RE.source, TEST_TITLE_RE.flags);
|
|
201
|
+
let m: RegExpExecArray | null;
|
|
202
|
+
while ((m = re.exec(text)) !== null) {
|
|
203
|
+
titles.push(m[2] ?? '');
|
|
204
|
+
}
|
|
205
|
+
return titles;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* A name-filtered vitest run whose target exists but carries no test title
|
|
210
|
+
* containing the filter — the oracle exits 0 on every test skipped, which a
|
|
211
|
+
* plain exit-code read cannot distinguish from every test passing.
|
|
212
|
+
*
|
|
213
|
+
* `null` whenever the shape does not match, the target cannot be resolved
|
|
214
|
+
* (nothing to read), or no title could be extracted at all (a parse miss,
|
|
215
|
+
* not evidence of absence) — in every one of those the finding would be a
|
|
216
|
+
* guess, and this function only reports what it read.
|
|
217
|
+
*/
|
|
218
|
+
function _nameFilterHasNoMatch(command: string): string | null {
|
|
219
|
+
const m = VITEST_NAME_FILTER_RE.exec(command);
|
|
220
|
+
if (m === null) return null;
|
|
221
|
+
const targetRaw = m[1] as string;
|
|
222
|
+
const name = (m[2] ?? m[3] ?? m[4] ?? '').trim();
|
|
223
|
+
if (name === '') return null;
|
|
224
|
+
const target = path.resolve(process.cwd(), targetRaw);
|
|
225
|
+
const files = _collectTestFiles(target);
|
|
226
|
+
if (files.length === 0) return null;
|
|
227
|
+
let sawAnyTitle = false;
|
|
228
|
+
for (const file of files) {
|
|
229
|
+
for (const title of _extractTitles(file)) {
|
|
230
|
+
sawAnyTitle = true;
|
|
231
|
+
if (title.includes(name)) return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!sawAnyTitle) return null;
|
|
235
|
+
return `\`-t ${name}\` matches no test title under ${targetRaw}: the run exits 0 with every test skipped`;
|
|
236
|
+
}
|
|
237
|
+
|
|
152
238
|
export function unfalsifiableReason(clause: VerifyClause): string | null {
|
|
153
239
|
if (clause.command === null) {
|
|
154
240
|
// A MANUAL clause asserting a QUANTITY nothing produced. Narrowed to a
|
|
@@ -176,6 +262,10 @@ export function unfalsifiableReason(clause: VerifyClause): string | null {
|
|
|
176
262
|
// An expectation that cannot compile never became one upstream.
|
|
177
263
|
}
|
|
178
264
|
}
|
|
265
|
+
|
|
266
|
+
const nameFilterReason = _nameFilterHasNoMatch(clause.command);
|
|
267
|
+
if (nameFilterReason !== null) return nameFilterReason;
|
|
268
|
+
|
|
179
269
|
return null;
|
|
180
270
|
}
|
|
181
271
|
|
|
@@ -17,7 +17,9 @@ import { execFileSync } from 'node:child_process';
|
|
|
17
17
|
import * as fs from 'node:fs';
|
|
18
18
|
import * as path from 'node:path';
|
|
19
19
|
|
|
20
|
+
import { load_agent_settings } from '../_lib/agent_settings.js';
|
|
20
21
|
import { hardenedSpawnEnv } from '../_lib/spawn_env.js';
|
|
22
|
+
import { EXT_LANG } from './types.js';
|
|
21
23
|
import { validateGraph } from './validate.js';
|
|
22
24
|
|
|
23
25
|
export type SourceKind = 'consumer' | 'scip' | 'native';
|
|
@@ -33,6 +35,44 @@ export interface SourceVerdict {
|
|
|
33
35
|
|
|
34
36
|
const CONSUMER_CANDIDATES = ['graph.json', 'code-graph.json', '.code-graph/graph.json'];
|
|
35
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Extra graph paths the CONSUMER declares, from `code_graph.consumer_index_paths`.
|
|
40
|
+
*
|
|
41
|
+
* The default list above stays generic on purpose — three filenames, none of
|
|
42
|
+
* them any particular tool's. A tool that writes its index somewhere else is
|
|
43
|
+
* reachable by the consumer naming the path, never by this package shipping a
|
|
44
|
+
* table of vendor locations: such a table is wrong the day a tool moves its
|
|
45
|
+
* file and wrong forever about one nobody thought of, and
|
|
46
|
+
* `check_no_external_sources` would fail the build for carrying it.
|
|
47
|
+
*
|
|
48
|
+
* Absolute paths and anything escaping the project root are dropped. A setting
|
|
49
|
+
* that could point the walk at `/etc` would be a path-traversal surface in a
|
|
50
|
+
* read a consumer did not ask for.
|
|
51
|
+
*/
|
|
52
|
+
export function consumerCandidates(root: string): string[] {
|
|
53
|
+
let declared: unknown;
|
|
54
|
+
try {
|
|
55
|
+
const settings = load_agent_settings({ cwd: root }) ?? {};
|
|
56
|
+
const section = (settings as Record<string, unknown>)['code_graph'];
|
|
57
|
+
declared =
|
|
58
|
+
section !== null && typeof section === 'object' && !Array.isArray(section)
|
|
59
|
+
? (section as Record<string, unknown>)['consumer_index_paths']
|
|
60
|
+
: undefined;
|
|
61
|
+
} catch {
|
|
62
|
+
declared = undefined;
|
|
63
|
+
}
|
|
64
|
+
const extra = Array.isArray(declared)
|
|
65
|
+
? declared.filter(
|
|
66
|
+
(p): p is string =>
|
|
67
|
+
typeof p === 'string' &&
|
|
68
|
+
p !== '' &&
|
|
69
|
+
!path.isAbsolute(p) &&
|
|
70
|
+
!path.normalize(p).startsWith('..'),
|
|
71
|
+
)
|
|
72
|
+
: [];
|
|
73
|
+
return [...CONSUMER_CANDIDATES, ...extra.filter((p) => !CONSUMER_CANDIDATES.includes(p))];
|
|
74
|
+
}
|
|
75
|
+
|
|
36
76
|
function gitLastCommitEpoch(root: string): number | null {
|
|
37
77
|
try {
|
|
38
78
|
const out = execFileSync('git', ['-C', root, 'log', '-1', '--format=%ct'], {
|
|
@@ -100,7 +140,7 @@ export function detectSources(root: string, nativeCache: string): SourceVerdict[
|
|
|
100
140
|
const abs = path.resolve(root);
|
|
101
141
|
const out: SourceVerdict[] = [];
|
|
102
142
|
|
|
103
|
-
for (const rel of
|
|
143
|
+
for (const rel of consumerCandidates(abs)) {
|
|
104
144
|
const p = path.join(abs, rel);
|
|
105
145
|
if (fs.existsSync(p)) {
|
|
106
146
|
const { ok, sha } = looksLikeGraph(p);
|
|
@@ -189,7 +229,12 @@ export function computeVerdict(root: string, nativeCache: string): VerdictJSON {
|
|
|
189
229
|
export const NATIVE_CACHE_REL = path.join('agents', 'runtime', 'state', 'code-graph-v1.json');
|
|
190
230
|
|
|
191
231
|
/**
|
|
192
|
-
* The
|
|
232
|
+
* The four-state staleness token every consumer of the graph reports.
|
|
233
|
+
*
|
|
234
|
+
* `edited` is the fourth and newest (`road-to-a-graph-that-feeds-the-gate` 2.3).
|
|
235
|
+
* Without it an uncommitted change to an indexed file read as `fresh` — the one
|
|
236
|
+
* state that says "nothing stands between this answer and the tree" — which is
|
|
237
|
+
* the reading most likely to be wrong while someone is editing.
|
|
193
238
|
*
|
|
194
239
|
* Lives HERE rather than in the PreToolUse hook that first needed it
|
|
195
240
|
* (`hooks/code_graph_context_hook.ts`, step 1.2). Phase 3's verbs must each
|
|
@@ -198,7 +243,73 @@ export const NATIVE_CACHE_REL = path.join('agents', 'runtime', 'state', 'code-gr
|
|
|
198
243
|
* the engine, never the other way round. The hook re-exports this so its own
|
|
199
244
|
* consumers are unaffected.
|
|
200
245
|
*/
|
|
201
|
-
export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
|
|
246
|
+
export type GraphState = 'absent' | 'fresh' | 'edited' | `behind:${number}`;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The working tree carries an uncommitted change to a file the extractor would
|
|
250
|
+
* index.
|
|
251
|
+
*
|
|
252
|
+
* WHY POINT-IN-TIME PORCELAIN AND NOT THE ARTIFACT'S MTIME. An mtime comparison
|
|
253
|
+
* looks cheaper and is wrong in the one direction that matters: restoring a
|
|
254
|
+
* stashed or checked-out file rewrites its mtime, so a tree put back exactly as
|
|
255
|
+
* the graph saw it would read stale forever and never return to `fresh`. The
|
|
256
|
+
* porcelain result describes a CONTENT difference, so a revert is visible as a
|
|
257
|
+
* revert.
|
|
258
|
+
*
|
|
259
|
+
* "Indexed paths" is read as *paths of the kind the extractor indexes* —
|
|
260
|
+
* `EXT_LANG`'s extensions — not as the node set of a loaded graph. Loading the
|
|
261
|
+
* graph to answer a freshness question would mean opening the index on every
|
|
262
|
+
* PreToolUse call this now runs on, which is the latency the Risk Register
|
|
263
|
+
* names; the extension filter answers the same question with no read. It can
|
|
264
|
+
* over-report (a `.ts` file the build excluded) and cannot under-report, and
|
|
265
|
+
* over-reporting `edited` only ever makes an answer look worth less than it is.
|
|
266
|
+
*
|
|
267
|
+
* Untracked files count. A source file that exists only in the working tree is
|
|
268
|
+
* precisely something the index cannot know about.
|
|
269
|
+
*
|
|
270
|
+
* `--untracked-files=all` IS LOAD-BEARING, and the default was wrong. Plain
|
|
271
|
+
* porcelain COLLAPSES an untracked directory to one entry — `?? src/` — which
|
|
272
|
+
* carries no extension, so the filter below skipped it and an entire new source
|
|
273
|
+
* tree read as `fresh`. A completion review reproduced exactly that, and it is
|
|
274
|
+
* the one direction the paragraph above promises cannot happen. The cost is
|
|
275
|
+
* enumerating untracked files rather than untracked directories; `.gitignore`
|
|
276
|
+
* still applies, so a vendored tree stays out of it.
|
|
277
|
+
*/
|
|
278
|
+
function hasUncommittedIndexedEdit(root: string): boolean {
|
|
279
|
+
let out: string;
|
|
280
|
+
try {
|
|
281
|
+
out = execFileSync('git', ['-C', root, 'status', '--porcelain', '--untracked-files=all'], {
|
|
282
|
+
env: hardenedSpawnEnv(),
|
|
283
|
+
encoding: 'utf-8',
|
|
284
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
285
|
+
// Both bounds are the review's: Node's 1 MB default would throw
|
|
286
|
+
// ENOBUFS on a large working tree, the catch below would return
|
|
287
|
+
// false, and the state would read `fresh` — a second silent
|
|
288
|
+
// under-report on a probe that runs at PreToolUse and at every stop.
|
|
289
|
+
// The timeout bounds the other failure: this probe sits in front of
|
|
290
|
+
// a tool call, so a hung git must not hold one up.
|
|
291
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
292
|
+
timeout: 5_000,
|
|
293
|
+
});
|
|
294
|
+
} catch {
|
|
295
|
+
// Not a repository, or the probe failed: nothing is known, and an
|
|
296
|
+
// unknown is reported as the state the caller already had.
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
for (const raw of out.split('\n')) {
|
|
300
|
+
if (raw.length < 4) continue;
|
|
301
|
+
// `XY <path>`; a rename or copy is `XY <old> -> <new>`, and the NEW path
|
|
302
|
+
// is the one on disk. Quotes appear under core.quotepath for non-ASCII.
|
|
303
|
+
let p = raw.slice(3);
|
|
304
|
+
const arrow = p.indexOf(' -> ');
|
|
305
|
+
if (arrow !== -1) p = p.slice(arrow + 4);
|
|
306
|
+
p = p.trim().replace(/^"|"$/g, '');
|
|
307
|
+
const dot = p.lastIndexOf('.');
|
|
308
|
+
if (dot === -1) continue;
|
|
309
|
+
if (p.slice(dot).toLowerCase() in EXT_LANG) return true;
|
|
310
|
+
}
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
202
313
|
|
|
203
314
|
/**
|
|
204
315
|
* Resolve the graph's state for `root`.
|
|
@@ -206,7 +317,10 @@ export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
|
|
|
206
317
|
* `absent` means no source at all — the silent case. A picked source whose
|
|
207
318
|
* staleness is UNKNOWN reads as `fresh`, mirroring {@link computeVerdict}'s own
|
|
208
319
|
* `picked.stale ? STALE : FRESH`: unknown is not treated as stale, because
|
|
209
|
-
* inventing a commit count would be worse than reporting none.
|
|
320
|
+
* inventing a commit count would be worse than reporting none. A source level
|
|
321
|
+
* with HEAD then reads `edited` instead of `fresh` while the working tree
|
|
322
|
+
* carries an uncommitted change to an indexable file — see
|
|
323
|
+
* {@link hasUncommittedIndexedEdit} for why that probe is porcelain, not mtime.
|
|
210
324
|
*
|
|
211
325
|
* `nativeCache` overrides where the native graph is looked for. It exists
|
|
212
326
|
* because a verb invoked with an explicit `--graph <path>` would otherwise
|
|
@@ -218,7 +332,13 @@ export type GraphState = 'absent' | 'fresh' | `behind:${number}`;
|
|
|
218
332
|
export function graphState(root: string, nativeCache?: string): GraphState {
|
|
219
333
|
const picked = pickSource(detectSources(root, nativeCache ?? path.join(root, NATIVE_CACHE_REL)));
|
|
220
334
|
if (!picked) return 'absent';
|
|
221
|
-
if (picked.stale
|
|
222
|
-
|
|
223
|
-
|
|
335
|
+
if (picked.stale === true) {
|
|
336
|
+
const behind = picked.commits_behind;
|
|
337
|
+
return `behind:${typeof behind === 'number' ? behind : 0}`;
|
|
338
|
+
}
|
|
339
|
+
// The commit count comes FIRST and wins: `behind:N` already says the index
|
|
340
|
+
// predates committed work, and reporting `edited` instead would hide the
|
|
341
|
+
// larger gap behind the smaller one. Only a graph level with HEAD has an
|
|
342
|
+
// uncommitted edit as its whole remaining distance.
|
|
343
|
+
return hasUncommittedIndexedEdit(root) ? 'edited' : 'fresh';
|
|
224
344
|
}
|