@event4u/agent-config 16.3.0 → 16.5.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 +178 -78
- package/README.md +2 -2
- package/agents/templates/.ai-council.yml.example +26 -8
- package/dist/agent-src/commands/analyze/inbox.md +10 -7
- 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/design.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 +1 -1
- package/dist/agent-src/commands/fix/ci.md +17 -3
- 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 +3 -3
- 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/next.md +10 -1
- package/dist/agent-src/commands/roadmap/process-full.md +52 -38
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +64 -14
- 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/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 +1 -1
- 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 +67 -52
- 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 +4 -10
- 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/design-antipatterns.md +1 -1
- package/dist/agent-src/guidelines/php/git.md +15 -2
- package/dist/agent-src/rules/active-remediation.md +0 -1
- 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 +0 -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 +0 -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 +0 -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 +5 -5
- 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 +2 -3
- package/dist/agent-src/rules/delegation-policy.md +2 -3
- package/dist/agent-src/rules/design-fidelity.md +0 -1
- 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 +0 -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 +0 -1
- package/dist/agent-src/rules/domain-safety-pii.md +0 -1
- package/dist/agent-src/rules/domain-safety-retention.md +0 -1
- package/dist/agent-src/rules/downstream-changes.md +0 -1
- package/dist/agent-src/rules/engineering-safety-floor.md +0 -1
- 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 +1 -2
- package/dist/agent-src/rules/finance-safety-floor.md +0 -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 +1 -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 +0 -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 +0 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +0 -1
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +0 -1
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
- package/dist/agent-src/rules/media-governance-routing.md +1 -2
- 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 +2 -3
- 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 +2 -3
- package/dist/agent-src/rules/question-not-instruction.md +0 -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 +3 -6
- 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 +0 -1
- package/dist/agent-src/rules/scale-discipline.md +0 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +0 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +0 -1
- 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 +0 -1
- package/dist/agent-src/rules/settings-ask-protocol.md +5 -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 +0 -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 +0 -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 +14 -48
- 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 +0 -1
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +0 -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 +0 -1
- package/dist/agent-src/scripts/gate_budget.ts +47 -23
- package/dist/agent-src/scripts/gate_execute.ts +12 -4
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +2 -0
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
- 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/bug-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/canvas-design/SKILL.md +4 -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-intelligence/references/integration-mapping.md +13 -10
- package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +1 -1
- package/dist/agent-src/skills/fe-design/references/design-patterns.md +49 -2
- package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +9 -0
- 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 +4 -2
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +16 -5
- package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
- package/dist/agent-src/skills/logo-generation/SKILL.md +12 -8
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
- package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +4 -4
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -2
- package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/svg-authoring/SKILL.md +318 -0
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +3 -1
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- 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/skills/wireframe/SKILL.md +5 -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/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/skill.md +1 -1
- package/dist/cli/commands/uiRender.js +201 -4
- package/dist/cli/commands/uiRenderAsset.js +1308 -0
- package/dist/cli/commands/uiRenderAssetCompare.js +752 -0
- package/dist/cli/commands/uiRenderAssetGrid.js +265 -0
- package/dist/cli/commands/uiRenderAssetGrounds.js +323 -0
- package/dist/cli/commands/uiRenderAssetIsolation.js +85 -0
- package/dist/cli/commands/uiRenderAssetTypes.js +145 -0
- package/dist/cli/main.js +47 -1
- package/dist/cli/registry.js +2 -1
- package/dist/cli-delegate/check_update_banner.js +195 -119
- package/dist/cli-delegate/{chunk-S4UMZNES.js → chunk-4DBG5K7M.js} +5 -5
- package/dist/cli-delegate/{chunk-TRI6DQZ6.js → chunk-5GPULQBE.js} +60 -42
- package/dist/cli-delegate/{chunk-JQVYKIZA.js → chunk-6SRJTYJS.js} +33 -177
- package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
- 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-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
- package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
- package/dist/cli-delegate/{chunk-NXEILF2K.js → chunk-F3QDG2GT.js} +481 -72
- package/dist/cli-delegate/{chunk-CQWX336L.js → chunk-G5VVIZRC.js} +3 -3
- package/dist/cli-delegate/{chunk-JY2I2DXV.js → chunk-H76PHZBI.js} +137 -60
- package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
- package/dist/cli-delegate/{chunk-LIYTLH6O.js → chunk-KXXWJTDO.js} +5 -10
- package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
- package/dist/cli-delegate/{chunk-S4YWNRKO.js → chunk-MDPPKQCQ.js} +34 -1
- package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
- package/dist/cli-delegate/{chunk-GKE7ZVFA.js → chunk-PWX7CKMD.js} +1 -1
- package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
- package/dist/cli-delegate/{chunk-RQNNW7IF.js → chunk-T7XSJSUQ.js} +433 -632
- package/dist/cli-delegate/{chunk-NQ7WT43P.js → chunk-TMWYUOK4.js} +75 -12
- package/dist/cli-delegate/{chunk-EEHDXSYD.js → chunk-WQWXGIWB.js} +12 -273
- package/dist/cli-delegate/{chunk-QLDHIPWR.js → chunk-XQTPXKFA.js} +1 -1
- 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 +489 -238
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +15 -12
- package/dist/cli-delegate/cmd_doctor_neighbours.js +11 -4
- package/dist/cli-delegate/cmd_explain.js +43 -19
- package/dist/cli-delegate/cmd_export.js +10 -10
- package/dist/cli-delegate/cmd_git_convention.js +1851 -0
- package/dist/cli-delegate/cmd_handoff.js +40 -21
- package/dist/cli-delegate/cmd_mcp_available.js +3 -2
- package/dist/cli-delegate/cmd_migrate.js +3 -3
- package/dist/cli-delegate/cmd_packs_active.js +4 -3
- package/dist/cli-delegate/cmd_prune.js +10 -10
- package/dist/cli-delegate/cmd_route_audit.js +7 -7
- package/dist/cli-delegate/cmd_route_explain.js +5 -5
- package/dist/cli-delegate/cmd_session_recycle.js +9 -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 +10 -10
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +10 -10
- package/dist/cli-delegate/cmd_uninstall.js +10 -10
- package/dist/cli-delegate/cmd_update.js +7 -7
- package/dist/cli-delegate/cmd_upgrade.js +7 -7
- package/dist/cli-delegate/cmd_validate.js +10 -10
- package/dist/cli-delegate/cmd_versions.js +5 -5
- package/dist/cli-delegate/gate_budget.js +1 -1
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +2 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +171 -107
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +7 -7
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +41 -22
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -11
- package/dist/hooks/dispatch.js +2520 -1924
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/hooks/svg_rules.chunk.cjs +1626 -0
- package/dist/hooks/svg_rules.chunk.cjs.sha256 +1 -0
- package/dist/install/install.mjs +462 -431
- package/dist/install/installThinLayer.js +40 -12
- package/dist/install/installedRuleLinks.js +105 -19
- 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 +3063 -2160
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +15 -120
- 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 +344 -18
- package/dist/scripts/_lib/package_root.js +68 -0
- package/dist/scripts/_lib/rule_law_section.js +1 -1
- package/dist/scripts/_lib/scan_scope.js +105 -0
- package/dist/scripts/_lib/settings_removed_keys.js +168 -0
- package/dist/scripts/_lib/svg_dom.js +284 -0
- package/dist/scripts/_lib/svg_geometry.js +477 -0
- package/dist/scripts/_lib/svg_motion.js +179 -0
- package/dist/scripts/_lib/svg_rules.js +1337 -0
- package/dist/scripts/_lib/svg_urls.js +67 -0
- package/dist/scripts/_lib/thin_rules.js +80 -3
- package/dist/scripts/lint_svg_asset.js +324 -0
- 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 +23 -81
- package/dist/shared/skillRanking.js +30 -4
- 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 +35 -65
- 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/design-antipatterns.md +1 -1
- package/docs/guidelines/php/git.md +15 -2
- package/package.json +4 -3
- package/src/agent-src/scripts/gate_budget.ts +47 -23
- package/src/agent-src/scripts/gate_execute.ts +12 -4
- 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/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/config/agent-settings.template.yml +79 -312
- 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 +3 -3
- package/src/config/discovery/packs.yml +17 -1
- package/src/config/evaluator-budgets.json +19 -6
- package/src/config/gate-coverage.yml +65 -23
- package/src/config/gate-violation-baselines.json +56 -16
- package/src/config/gitignore-block.txt +19 -0
- package/src/config/hook-bundle-budget.json +1 -1
- package/src/config/release-gate-locality.yml +2 -1
- package/src/config/routing-coverage-seed.json +55 -6
- package/src/config/rule-law-ceilings.json +12 -6
- package/src/config/rule-obligations.json +833 -0
- package/src/install/installThinLayer.ts +76 -10
- package/src/install/installedRuleLinks.ts +105 -17
- 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 +10 -10
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +133 -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 +37 -2
- package/src/scripts/_lib/agent_settings.ts +15 -124
- package/src/scripts/_lib/blocked_by_marker.ts +1 -1
- package/src/scripts/_lib/compile_time_toggles.ts +12 -21
- package/src/scripts/_lib/dispatch_import_closure.ts +163 -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/global_deploy_inventory.ts +74 -0
- package/src/scripts/_lib/graph_feeder_record.ts +236 -13
- package/src/scripts/_lib/installed_layer.ts +448 -23
- package/src/scripts/_lib/knowledge_global.ts +14 -1
- package/src/scripts/_lib/module_reach.ts +456 -0
- package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +8 -10
- 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/rule_law_section.ts +1 -1
- 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/svg_dom.ts +318 -0
- package/src/scripts/_lib/svg_geometry.ts +480 -0
- package/src/scripts/_lib/svg_motion.ts +208 -0
- package/src/scripts/_lib/svg_rules.ts +1453 -0
- package/src/scripts/_lib/svg_urls.ts +72 -0
- package/src/scripts/_lib/test_red_state.ts +5 -0
- package/src/scripts/_lib/thin_rules.ts +83 -3
- package/src/scripts/_lib/touched_file_quality.ts +142 -6
- package/src/scripts/_lib/verification_command.ts +59 -0
- package/src/scripts/_lib/verify_clause.ts +27 -17
- package/src/scripts/_lib/worker_budget.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +16 -1
- package/src/scripts/ai_council/config.ts +7 -7
- 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_team/config.ts +11 -16
- package/src/scripts/audit_user_type_axis.ts +20 -8
- 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/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_evaluator_budgets.ts +4 -0
- package/src/scripts/check_finding_dispositions.ts +88 -25
- 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 +107 -0
- package/src/scripts/check_kernel_edit_ratified.ts +86 -6
- package/src/scripts/check_pack_size.ts +1 -1
- package/src/scripts/check_release_manifest_content.ts +189 -0
- package/src/scripts/check_standing_rule_delivery.ts +96 -0
- package/src/scripts/check_suppression_hygiene.ts +2 -5
- 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/command_suggester/settings.ts +8 -108
- package/src/scripts/command_suggester/types.ts +4 -5
- 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/explain_run.ts +8 -13
- package/src/scripts/generate_git_convention_grammar.ts +127 -0
- package/src/scripts/generate_host_cost_table.ts +20 -3
- package/src/scripts/handoff_context_hook.ts +86 -37
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +25 -6
- package/src/scripts/hooks/block_config_weakening.ts +48 -5
- package/src/scripts/hooks/block_plumbing_writes.ts +8 -4
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +16 -1
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
- package/src/scripts/hooks/design_pass_hook.ts +157 -3
- package/src/scripts/hooks/evidence_independence.ts +12 -4
- package/src/scripts/hooks/mcp_usage_observation_hook.ts +121 -0
- package/src/scripts/hooks/push_settle_hook.ts +4 -3
- package/src/scripts/hooks/rule_inject_hook.ts +44 -3
- package/src/scripts/hooks/state_io.ts +8 -4
- package/src/scripts/hooks/svg_obligation.ts +497 -0
- package/src/scripts/hooks/svg_rules_loader.ts +133 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +7 -46
- package/src/scripts/hooks/turn_end_gate_hook.ts +6 -3
- package/src/scripts/install-hooks.sh +42 -14
- package/src/scripts/install.ts +7 -31
- package/src/scripts/lint_blocker_citations.ts +198 -0
- package/src/scripts/lint_consolidation_lineage.ts +6 -3
- package/src/scripts/lint_design_quality.ts +60 -12
- package/src/scripts/lint_evidence_artifacts.ts +9 -0
- package/src/scripts/lint_hook_concern_budget.ts +10 -21
- package/src/scripts/lint_motion_authority_drift.ts +27 -0
- package/src/scripts/lint_pack_boundaries.ts +406 -28
- 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 +151 -21
- package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
- package/src/scripts/lint_settings_classes.ts +1 -1
- package/src/scripts/lint_svg_asset.ts +365 -0
- package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
- package/src/scripts/lint_workflow_security.ts +12 -1
- package/src/scripts/measure_skill_ranker_baseline.ts +5 -0
- package/src/scripts/model_rule_injection.ts +3 -3
- 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/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_installed_rule_links.ts +118 -1
- package/src/scripts/report_module_reach.ts +212 -0
- package/src/scripts/report_obligation_mechanism.ts +16 -18
- package/src/scripts/report_parked_blockers.ts +222 -0
- package/src/scripts/report_required_checks_drift.ts +196 -0
- package/src/scripts/report_skill_ranker_confusion.ts +103 -2
- package/src/scripts/report_standing_payload_by_host.ts +1 -1
- package/src/scripts/routing_doctor.ts +2 -2
- package/src/scripts/schemas/agent-settings.schema.json +17 -31
- package/src/scripts/schemas/command.schema.json +1 -1
- package/src/scripts/schemas/skill.schema.json +1 -1
- package/src/scripts/self_review_gate.ts +39 -2
- package/src/scripts/skill_tools/score_skill_relevance.ts +28 -19
- package/src/scripts/sync_pr_branch.ts +403 -132
- package/src/scripts/trigger_eval_grandfather.json +0 -16
- package/src/server/schemas/settings.ts +33 -177
- package/src/shared/skillRanking.ts +53 -4
- package/dist/cli-delegate/chunk-NYX3L2PZ.js +0 -99
- 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,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The static import closure of the hook dispatcher, and the class of each
|
|
3
|
+
* module in it.
|
|
4
|
+
*
|
|
5
|
+
* `check_kernel_edit_ratified` derives part of its watched set from this
|
|
6
|
+
* reading: a module the dispatcher reaches that decides an exit code needs a
|
|
7
|
+
* ratification record, whichever file the logic currently lives in. A hand
|
|
8
|
+
* list stayed correct until one function moved files; a derived set follows it.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately static and deliberately narrow, so the reading is reproducible
|
|
11
|
+
* from a tree alone:
|
|
12
|
+
*
|
|
13
|
+
* - only RELATIVE specifiers (`./x.js`, `../_lib/y.js`) are followed —
|
|
14
|
+
* packages and `node:` builtins are not this repository's plumbing;
|
|
15
|
+
* - `import … from`, `export … from` and side-effect `import '…'` count;
|
|
16
|
+
* dynamic `import()` does not, because its target is not decidable here;
|
|
17
|
+
* - the walk STOPS at the concern table. Every module `concern_registry.ts`
|
|
18
|
+
* imports is a concern, classed `concern` and not walked into, because
|
|
19
|
+
* concerns stay outside the fence — a governance concern is gated by its
|
|
20
|
+
* own `block_*` pattern, and widening to every concern would turn routine
|
|
21
|
+
* edits into record-carrying ones.
|
|
22
|
+
*
|
|
23
|
+
* Classes, decided from the module's own source text:
|
|
24
|
+
*
|
|
25
|
+
* - `verdict` — names an exit-code constant (`EXIT_ALLOW`, `EXIT_BLOCK`,
|
|
26
|
+
* `EXIT_WARN`, `EXIT_USAGE`), or exports a function whose name says it
|
|
27
|
+
* decides a refusal (`deny…`, `…block…`, `…verdict…`, `…fail_closed…`).
|
|
28
|
+
* The constants are how the dispatcher turns a crash, a timeout or a stdin
|
|
29
|
+
* failure into the code a host acts on; the second signal catches a policy
|
|
30
|
+
* that returns a boolean the dispatcher then maps — `denyOnStdinFailure`
|
|
31
|
+
* names no constant and still decides whether a failed read refuses.
|
|
32
|
+
* - `payload` — names the payload a concern receives (`payload`, `stdin`).
|
|
33
|
+
* - `neither` — everything else (timing, state I/O, logging).
|
|
34
|
+
* - `concern` — imported by the concern table; outside the fence.
|
|
35
|
+
*
|
|
36
|
+
* The classes read NAMES, not data flow. A module already in the closure as
|
|
37
|
+
* `payload` or `neither` that gains verdict-influencing logic under a neutral
|
|
38
|
+
* name is not reclassified; the gate covers the arrival of such a module
|
|
39
|
+
* (`closureArrivals`) and its declassification (the base∪head union), not this.
|
|
40
|
+
* Closing it needs call-graph analysis — a different design, not a tweak.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import * as fs from 'node:fs';
|
|
44
|
+
import * as path from 'node:path';
|
|
45
|
+
|
|
46
|
+
/** The dispatcher, repo-relative. The closure's root. */
|
|
47
|
+
export const DISPATCHER_PATH = 'src/scripts/hooks/dispatch_hook.ts';
|
|
48
|
+
|
|
49
|
+
/** The concern table. Its imports are concerns, the walk's boundary. */
|
|
50
|
+
export const CONCERN_REGISTRY_PATH = 'src/scripts/hooks/concern_registry.ts';
|
|
51
|
+
|
|
52
|
+
export type ModuleClass = 'verdict' | 'payload' | 'neither' | 'concern';
|
|
53
|
+
|
|
54
|
+
export interface ClosureEntry {
|
|
55
|
+
/** Repo-relative POSIX path. */
|
|
56
|
+
path: string;
|
|
57
|
+
class: ModuleClass;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const EXIT_CONSTANT_RE = /\bEXIT_(?:ALLOW|BLOCK|WARN|USAGE)\b/;
|
|
61
|
+
const VERDICT_EXPORT_RE =
|
|
62
|
+
/\bexport\s+(?:async\s+)?(?:function\s+|const\s+)([A-Za-z_$][\w$]*)/g;
|
|
63
|
+
const VERDICT_NAME_RE = /deny|block|verdict|fail_?closed|refus/i;
|
|
64
|
+
const PAYLOAD_RE = /\b(?:payload|stdin)\b/i;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Relative specifiers in a module's source. Comments are stripped first so a
|
|
68
|
+
* commented-out import does not count as an edge.
|
|
69
|
+
*/
|
|
70
|
+
export function relativeSpecifiers(source: string): string[] {
|
|
71
|
+
const stripped = source.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1');
|
|
72
|
+
const out: string[] = [];
|
|
73
|
+
const re = /(?:\bimport\s+(?:type\s+)?(?:[\s\S]*?\bfrom\s*)?|\bexport\s+(?:type\s+)?[\s\S]*?\bfrom\s*)['"](\.{1,2}\/[^'"]+)['"]/g;
|
|
74
|
+
let m: RegExpExecArray | null;
|
|
75
|
+
while ((m = re.exec(stripped)) !== null) {
|
|
76
|
+
if (m[1] !== undefined) {
|
|
77
|
+
out.push(m[1]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Resolve a `.js` specifier from `fromRel` to the `.ts` source on disk. */
|
|
84
|
+
function resolveSpecifier(root: string, fromRel: string, spec: string): string | null {
|
|
85
|
+
const base = path.posix.join(path.posix.dirname(fromRel), spec);
|
|
86
|
+
const candidates = [base.replace(/\.js$/, '.ts'), base, `${base}.ts`, `${base}/index.ts`];
|
|
87
|
+
for (const c of candidates) {
|
|
88
|
+
const norm = path.posix.normalize(c);
|
|
89
|
+
if (fs.existsSync(path.join(root, norm)) && fs.statSync(path.join(root, norm)).isFile()) {
|
|
90
|
+
return norm;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Classify one module from its source text. Never returns `concern`. */
|
|
97
|
+
export function classifySource(source: string): Exclude<ModuleClass, 'concern'> {
|
|
98
|
+
if (EXIT_CONSTANT_RE.test(source)) {
|
|
99
|
+
return 'verdict';
|
|
100
|
+
}
|
|
101
|
+
for (const m of source.matchAll(VERDICT_EXPORT_RE)) {
|
|
102
|
+
if (VERDICT_NAME_RE.test(m[1] ?? '')) {
|
|
103
|
+
return 'verdict';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (PAYLOAD_RE.test(source)) {
|
|
107
|
+
return 'payload';
|
|
108
|
+
}
|
|
109
|
+
return 'neither';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Walk the closure from the dispatcher under `root`. Returns `[]` when the
|
|
114
|
+
* dispatcher is absent, so a fixture tree without one yields an empty set
|
|
115
|
+
* rather than an error. The dispatcher itself is not in the result — it is
|
|
116
|
+
* already watched by name.
|
|
117
|
+
*/
|
|
118
|
+
export function dispatchImportClosure(root: string, entry: string = DISPATCHER_PATH): ClosureEntry[] {
|
|
119
|
+
if (!fs.existsSync(path.join(root, entry))) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const seen = new Map<string, ModuleClass>();
|
|
123
|
+
const queue: string[] = [entry];
|
|
124
|
+
const visited = new Set<string>();
|
|
125
|
+
while (queue.length > 0) {
|
|
126
|
+
const rel = queue.shift() as string;
|
|
127
|
+
if (visited.has(rel)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
visited.add(rel);
|
|
131
|
+
const source = fs.readFileSync(path.join(root, rel), 'utf8');
|
|
132
|
+
if (rel !== entry) {
|
|
133
|
+
seen.set(rel, classifySource(source));
|
|
134
|
+
}
|
|
135
|
+
const isRegistry = rel === CONCERN_REGISTRY_PATH;
|
|
136
|
+
for (const spec of relativeSpecifiers(source)) {
|
|
137
|
+
const target = resolveSpecifier(root, rel, spec);
|
|
138
|
+
if (target === null || target === entry) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (isRegistry) {
|
|
142
|
+
if (!seen.has(target)) {
|
|
143
|
+
seen.set(target, 'concern');
|
|
144
|
+
}
|
|
145
|
+
visited.add(target);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (!visited.has(target)) {
|
|
149
|
+
queue.push(target);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return [...seen.entries()]
|
|
154
|
+
.map(([p, c]) => ({ path: p, class: c }))
|
|
155
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** The verdict-deciding modules of the closure — the part the gate watches. */
|
|
159
|
+
export function verdictModules(root: string): string[] {
|
|
160
|
+
return dispatchImportClosure(root)
|
|
161
|
+
.filter((e) => e.class === 'verdict')
|
|
162
|
+
.map((e) => e.path);
|
|
163
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one reading of a `--base` value, shared by `sync_pr_branch` and
|
|
3
|
+
* `check_branch_freshness`.
|
|
4
|
+
*
|
|
5
|
+
* The two resolvers used to accept different spellings: one prefixed every
|
|
6
|
+
* value with `origin/`, the other asked the server for `refs/heads/<value>`
|
|
7
|
+
* verbatim. A name copied from one tool's output into the other then named a
|
|
8
|
+
* ref nobody has (`origin/origin/main`, `refs/heads/origin/main`), and the
|
|
9
|
+
* freshness gate read that absent ref as an unreachable remote and passed.
|
|
10
|
+
*
|
|
11
|
+
* A value that already names where it lives is kept as given: a
|
|
12
|
+
* remote-tracking ref and `<remote>/x` for a configured remote. `refs/heads/x`
|
|
13
|
+
* names the branch on origin, so it maps to `refs/remotes/origin/x`: the local
|
|
14
|
+
* branch of that name is the same clone-time copy a bare name avoids, and a
|
|
15
|
+
* fetch never updates it. Anything else is a branch name on origin, slashes
|
|
16
|
+
* included, because `release/1.x` is a branch name and not a remote called
|
|
17
|
+
* `release`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface BaseRef {
|
|
21
|
+
/** The remote the server-side SHA is asked of. */
|
|
22
|
+
readonly remote: string;
|
|
23
|
+
/** The branch name on that remote. */
|
|
24
|
+
readonly branch: string;
|
|
25
|
+
/** The ref git operations use locally: as given, or `origin/<branch>` for a bare name. */
|
|
26
|
+
readonly ref: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const REMOTE_TRACKING = 'refs/remotes/';
|
|
30
|
+
const LOCAL_HEADS = 'refs/heads/';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The usage error for a `--base` given a blank value, or null for one that
|
|
34
|
+
* names something. Every tool that accepts `--base` rejects a blank one: an
|
|
35
|
+
* unset variable expands to nothing, and reading that as "no override" judged
|
|
36
|
+
* the run against the default branch without a word.
|
|
37
|
+
*/
|
|
38
|
+
export function blankBaseError(value: string): string | null {
|
|
39
|
+
return value.trim() === '' ? '--base was given an empty value — name the base branch (an unset variable expands to nothing); nothing was read or merged' : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The usage error for any `--base` value that must not reach git: a blank one,
|
|
44
|
+
* or one whose branch name starts with `-`, which git would read as an option.
|
|
45
|
+
* No branch can carry that name (`git check-ref-format --branch` refuses it).
|
|
46
|
+
*/
|
|
47
|
+
export function baseValueError(value: string, remotes: readonly string[] = []): string | null {
|
|
48
|
+
const blank = blankBaseError(value);
|
|
49
|
+
if (blank !== null) return blank;
|
|
50
|
+
const v = value.trim();
|
|
51
|
+
const branch = v.startsWith('-') ? v : (parseBaseRef(v, remotes)?.branch ?? v);
|
|
52
|
+
return branch.startsWith('-') ? `--base ${JSON.stringify(v)} names a branch that starts with "-", which git reads as an option — no branch has that name; nothing was read or merged` : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Read a `--base` value; null when it is empty. `remotes` are the configured remote names. */
|
|
56
|
+
export function parseBaseRef(value: string, remotes: readonly string[] = []): BaseRef | null {
|
|
57
|
+
const v = value.trim();
|
|
58
|
+
if (v === '') return null;
|
|
59
|
+
if (v.startsWith(LOCAL_HEADS) && v.length > LOCAL_HEADS.length) {
|
|
60
|
+
const branch = v.slice(LOCAL_HEADS.length);
|
|
61
|
+
return { remote: 'origin', branch, ref: `${REMOTE_TRACKING}origin/${branch}` };
|
|
62
|
+
}
|
|
63
|
+
if (v.startsWith('refs/')) return splitResolvedRef(v);
|
|
64
|
+
const slash = v.indexOf('/');
|
|
65
|
+
const known = new Set(['origin', ...remotes]);
|
|
66
|
+
if (slash > 0 && slash < v.length - 1 && known.has(v.slice(0, slash))) {
|
|
67
|
+
return { remote: v.slice(0, slash), branch: v.slice(slash + 1), ref: v };
|
|
68
|
+
}
|
|
69
|
+
return { remote: 'origin', branch: v, ref: `origin/${v}` };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Split a ref that was already resolved by `parseBaseRef` or reported by git
|
|
74
|
+
* (`origin/main`, `refs/heads/main`). A full ref outside the branch namespaces
|
|
75
|
+
* keeps its whole name as the branch, so the server answers it as unknown.
|
|
76
|
+
*/
|
|
77
|
+
export function splitResolvedRef(ref: string): BaseRef {
|
|
78
|
+
if (ref.startsWith(LOCAL_HEADS)) return { remote: 'origin', branch: ref.slice(LOCAL_HEADS.length), ref };
|
|
79
|
+
if (ref.startsWith(REMOTE_TRACKING)) {
|
|
80
|
+
const rest = ref.slice(REMOTE_TRACKING.length);
|
|
81
|
+
const slash = rest.indexOf('/');
|
|
82
|
+
if (slash > 0) return { remote: rest.slice(0, slash), branch: rest.slice(slash + 1), ref };
|
|
83
|
+
}
|
|
84
|
+
if (ref.startsWith('refs/')) return { remote: 'origin', branch: ref, ref };
|
|
85
|
+
const slash = ref.indexOf('/');
|
|
86
|
+
return slash > 0 ? { remote: ref.slice(0, slash), branch: ref.slice(slash + 1), ref } : { remote: 'origin', branch: ref, ref: `origin/${ref}` };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** `<remote>/<branch>`, the name a human reads and `task push-ready BASE=` accepts. */
|
|
90
|
+
export function displayBase(b: BaseRef): string {
|
|
91
|
+
return `${b.remote}/${b.branch}`;
|
|
92
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one reader of the `git.*` convention keys.
|
|
3
|
+
*
|
|
4
|
+
* `load_agent_settings` merges a layer that does not parse as if it were absent
|
|
5
|
+
* and drops user-global keys off its whitelist without a word, which is right
|
|
6
|
+
* for a setting whose default is harmless and wrong for these three: a team that
|
|
7
|
+
* declares `rebase` and gets a merge commit because an unrelated line elsewhere
|
|
8
|
+
* in the file has an unclosed bracket has had its convention overridden by a
|
|
9
|
+
* default nobody chose. So every key is reported with one of six states, and a
|
|
10
|
+
* caller that acts on the value refuses on anything but `valid` or `absent`:
|
|
11
|
+
*
|
|
12
|
+
* - `valid` — the deciding layer parsed and the value is allowed;
|
|
13
|
+
* - `absent` — no layer sets the key; the template default is reported;
|
|
14
|
+
* - `malformed` — a layer at or above the deciding one does not parse, so the
|
|
15
|
+
* value is unknowable;
|
|
16
|
+
* - `invalid` — the deciding layer sets a value the schema does not allow;
|
|
17
|
+
* - `discarded` — only a user-global file sets the key, and the loader drops
|
|
18
|
+
* user-global keys that are not whitelisted;
|
|
19
|
+
* - `unresolvable` — the commit a committed declaration must be read at cannot
|
|
20
|
+
* be resolved, so whether it declares anything is unknown.
|
|
21
|
+
*
|
|
22
|
+
* Where the layers come from is a {@link GitConventionSource}, so a reader of a
|
|
23
|
+
* committed declaration can replace the checkout cascade without touching the
|
|
24
|
+
* state logic.
|
|
25
|
+
*/
|
|
26
|
+
import { spawnSync } from 'node:child_process';
|
|
27
|
+
import { createRequire } from 'node:module';
|
|
28
|
+
import * as fs from 'node:fs';
|
|
29
|
+
|
|
30
|
+
import type * as YamlModule from 'yaml';
|
|
31
|
+
|
|
32
|
+
import { settings_layer_states, template_defaults, user_global_settings_paths } from './agent_settings.js';
|
|
33
|
+
|
|
34
|
+
const _require = createRequire(import.meta.url);
|
|
35
|
+
|
|
36
|
+
export const GIT_CONVENTION_KEYS = ['commit_format', 'branch_pattern', 'update_strategy'] as const;
|
|
37
|
+
export type GitConventionKey = (typeof GIT_CONVENTION_KEYS)[number];
|
|
38
|
+
|
|
39
|
+
export type GitConventionState = 'valid' | 'absent' | 'malformed' | 'invalid' | 'discarded' | 'unresolvable';
|
|
40
|
+
|
|
41
|
+
/** Mirrors the enums in `agent-settings.schema.json`; a test pins the parity. */
|
|
42
|
+
export const GIT_CONVENTION_ENUMS: Partial<Record<GitConventionKey, readonly string[]>> = {
|
|
43
|
+
commit_format: ['ticket-scope', 'ticket-conventional'],
|
|
44
|
+
update_strategy: ['merge', 'rebase'],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type GitConventionReason =
|
|
48
|
+
| 'git-convention-malformed'
|
|
49
|
+
| 'git-convention-invalid'
|
|
50
|
+
| 'git-convention-discarded'
|
|
51
|
+
| 'git-convention-unresolvable';
|
|
52
|
+
|
|
53
|
+
export interface GitConventionReading {
|
|
54
|
+
key: GitConventionKey;
|
|
55
|
+
value: string | null;
|
|
56
|
+
source: string | null;
|
|
57
|
+
state: GitConventionState;
|
|
58
|
+
reason: GitConventionReason | null;
|
|
59
|
+
detail: string | null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface GitConventionLayer {
|
|
63
|
+
path: string;
|
|
64
|
+
parsed: 'absent' | 'valid' | 'malformed';
|
|
65
|
+
data: unknown;
|
|
66
|
+
/** False for a layer whose `git.*` values the loader discards. */
|
|
67
|
+
carries: boolean;
|
|
68
|
+
/** Why a `malformed` layer is unknown: it does not parse, or its document is not a map. */
|
|
69
|
+
why?: string;
|
|
70
|
+
/** Set when the document parses but is not the shape the file is read in; every key reads `invalid`. */
|
|
71
|
+
shapeError?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface GitConventionSource {
|
|
75
|
+
/** Every layer, lowest precedence first. */
|
|
76
|
+
layers(): GitConventionLayer[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export type GitConventionDefaults = Partial<Record<GitConventionKey, string>>;
|
|
80
|
+
|
|
81
|
+
function _parse(p: string): Pick<GitConventionLayer, 'parsed' | 'data' | 'why'> {
|
|
82
|
+
let text: string;
|
|
83
|
+
try {
|
|
84
|
+
if (!fs.statSync(p).isFile()) return { parsed: 'absent', data: null };
|
|
85
|
+
text = fs.readFileSync(p, 'utf-8');
|
|
86
|
+
} catch (err) {
|
|
87
|
+
if ((err as NodeJS.ErrnoException).code === 'ENOENT') return { parsed: 'absent', data: null };
|
|
88
|
+
return { parsed: 'malformed', data: null, why: 'the file cannot be read' };
|
|
89
|
+
}
|
|
90
|
+
return parseLayerText(text);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Where the parse failed. An unquoted pattern (`{ticket}-{slug}`) is a flow
|
|
95
|
+
* mapping to YAML, and the error says nothing about quoting.
|
|
96
|
+
*/
|
|
97
|
+
function _parseFailure(text: string, err: unknown): string {
|
|
98
|
+
const line = (err as { linePos?: { line: number }[] }).linePos?.[0]?.line;
|
|
99
|
+
if (line === undefined) return 'the file does not parse';
|
|
100
|
+
const quote = (text.split('\n')[line - 1] ?? '').includes('{') ? `; a value containing \`{\` must be quoted, e.g. ${_quoteExample('branch_pattern')}` : '';
|
|
101
|
+
return `the file does not parse at line ${line}${quote}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function _quoteExample(key: GitConventionKey): string {
|
|
105
|
+
return `${key}: "${key === 'branch_pattern' ? '{ticket}-{slug}' : (GIT_CONVENTION_ENUMS[key]?.[0] ?? '…')}"`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** One layer's text, parsed the way the settings loader parses a file. */
|
|
109
|
+
export function parseLayerText(text: string): Pick<GitConventionLayer, 'parsed' | 'data' | 'why'> {
|
|
110
|
+
let data: unknown;
|
|
111
|
+
try {
|
|
112
|
+
const YAML = _require('yaml') as typeof YamlModule;
|
|
113
|
+
data = YAML.parse(text, { version: '1.1' });
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return { parsed: 'malformed', data: null, why: _parseFailure(text, err) };
|
|
116
|
+
}
|
|
117
|
+
if (data === null || data === undefined) return { parsed: 'valid', data: {} };
|
|
118
|
+
// The loader ignores a document that is not a map, which is the same silent
|
|
119
|
+
// fallback as a parse error.
|
|
120
|
+
if (typeof data !== 'object' || Array.isArray(data)) return { parsed: 'malformed', data: null, why: 'the document is not a map' };
|
|
121
|
+
return { parsed: 'valid', data };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Explicit files: the user-global ones carry nothing, the developer ones carry. */
|
|
125
|
+
export function fileSource(files: { userGlobal?: readonly string[]; developer?: readonly string[] }): GitConventionSource {
|
|
126
|
+
return {
|
|
127
|
+
layers: () => [
|
|
128
|
+
...(files.userGlobal ?? []).map((p) => ({ path: p, carries: false, ..._parse(p) })),
|
|
129
|
+
...(files.developer ?? []).map((p) => ({ path: p, carries: true, ..._parse(p) })),
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** The layers `load_agent_settings({ cwd })` reads for the checkout at `cwd`. */
|
|
135
|
+
export function checkoutSource(cwd: string): GitConventionSource {
|
|
136
|
+
return {
|
|
137
|
+
layers: () => {
|
|
138
|
+
const userGlobalCount = user_global_settings_paths().length;
|
|
139
|
+
const all = settings_layer_states({ cwd }).map((l) => l.path);
|
|
140
|
+
return fileSource({ userGlobal: all.slice(0, userGlobalCount), developer: all.slice(userGlobalCount) }).layers();
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type Lookup = { present: false } | { present: true; value: unknown } | { present: true; notAMap: true };
|
|
146
|
+
|
|
147
|
+
function _lookup(data: unknown, key: GitConventionKey): Lookup {
|
|
148
|
+
if (data === null || typeof data !== 'object') return { present: false };
|
|
149
|
+
const git = (data as Record<string, unknown>).git;
|
|
150
|
+
if (git === undefined || git === null) return { present: false };
|
|
151
|
+
if (typeof git !== 'object' || Array.isArray(git)) return { present: true, notAMap: true };
|
|
152
|
+
const value = (git as Record<string, unknown>)[key];
|
|
153
|
+
if (value === undefined || value === null) return { present: false };
|
|
154
|
+
return { present: true, value };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const BRANCH_PLACEHOLDERS = ['type', 'ticket', 'slug'] as const;
|
|
158
|
+
const BRANCH_SAMPLE: Record<(typeof BRANCH_PLACEHOLDERS)[number], string> = {
|
|
159
|
+
type: 'feat',
|
|
160
|
+
ticket: 'DEV-1234',
|
|
161
|
+
slug: 'sample-change',
|
|
162
|
+
};
|
|
163
|
+
/** A rendered name reaches shell commands, so the literal alphabet is closed. */
|
|
164
|
+
const BRANCH_LITERAL = /^[A-Za-z0-9._/-]*$/;
|
|
165
|
+
|
|
166
|
+
/** The pattern with every placeholder filled from a fixed sample. */
|
|
167
|
+
export function renderBranchSample(pattern: string): string {
|
|
168
|
+
return pattern.replace(/\{(type|ticket|slug)\}/g, (_m, name: keyof typeof BRANCH_SAMPLE) => BRANCH_SAMPLE[name]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function _branchPatternReason(pattern: string): string | null {
|
|
172
|
+
if (pattern === '') return 'the pattern is empty';
|
|
173
|
+
const literal = pattern.replace(/\{([^{}]*)\}/g, (match, name: string) => {
|
|
174
|
+
return (BRANCH_PLACEHOLDERS as readonly string[]).includes(name) ? '' : `\u0000${match}`;
|
|
175
|
+
});
|
|
176
|
+
const unknown = /\u0000(\{[^{}]*\})/.exec(literal);
|
|
177
|
+
if (unknown !== null) {
|
|
178
|
+
return `unknown placeholder ${unknown[1]}; allowed: ${BRANCH_PLACEHOLDERS.map((p) => `{${p}}`).join(', ')}`;
|
|
179
|
+
}
|
|
180
|
+
if (/[{}]/.test(literal)) return 'an unbalanced brace';
|
|
181
|
+
if (!BRANCH_LITERAL.test(literal)) {
|
|
182
|
+
const bad = [...new Set(literal.replace(/[A-Za-z0-9._/-]/g, ''))].join('');
|
|
183
|
+
return `literal character(s) ${JSON.stringify(bad)} outside [A-Za-z0-9._/-]`;
|
|
184
|
+
}
|
|
185
|
+
if (!pattern.includes('{slug}')) return 'the pattern must contain {slug}';
|
|
186
|
+
const sample = renderBranchSample(pattern);
|
|
187
|
+
const check = spawnSync('git', ['check-ref-format', '--branch', sample], { encoding: 'utf8' });
|
|
188
|
+
// Without git the closed alphabet above is the whole check.
|
|
189
|
+
if (check.error === undefined && check.status !== 0) {
|
|
190
|
+
return `the sample \`${sample}\` fails git check-ref-format --branch`;
|
|
191
|
+
}
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Why `value` is not allowed for `key`, or null when it is. */
|
|
196
|
+
export function invalidReason(key: GitConventionKey, value: string): string | null {
|
|
197
|
+
// The schema neither trims nor folds case, so neither does this check.
|
|
198
|
+
if (value !== value.trim()) return `\`${value}\` has leading or trailing whitespace`;
|
|
199
|
+
const allowed = GIT_CONVENTION_ENUMS[key];
|
|
200
|
+
if (allowed !== undefined) {
|
|
201
|
+
if (allowed.includes(value)) return null;
|
|
202
|
+
const caseOnly = allowed.includes(value.toLowerCase()) ? ' (values are case-sensitive)' : '';
|
|
203
|
+
return `\`${value}\` is not one of ${allowed.map((v) => `\`${v}\``).join(', ')}${caseOnly}`;
|
|
204
|
+
}
|
|
205
|
+
return _branchPatternReason(value);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function _defaults(): GitConventionDefaults {
|
|
209
|
+
const git = (template_defaults() as { git?: Record<string, unknown> }).git ?? {};
|
|
210
|
+
const out: GitConventionDefaults = {};
|
|
211
|
+
for (const key of GIT_CONVENTION_KEYS) {
|
|
212
|
+
if (typeof git[key] === 'string') out[key] = git[key] as string;
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** The template default for a key, or null when the template sets none. */
|
|
218
|
+
export function conventionDefault(key: GitConventionKey): string | null {
|
|
219
|
+
return _defaults()[key] ?? null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function conventionReading(
|
|
223
|
+
key: GitConventionKey,
|
|
224
|
+
state: GitConventionState,
|
|
225
|
+
value: string | null,
|
|
226
|
+
source: string | null,
|
|
227
|
+
detail: string | null = null,
|
|
228
|
+
): GitConventionReading {
|
|
229
|
+
const reason: GitConventionReason | null = isRefusal(state) ? (`git-convention-${state}` as GitConventionReason) : null;
|
|
230
|
+
return { key, value, source, state, reason, detail };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function readGitConventionKey(
|
|
234
|
+
key: GitConventionKey,
|
|
235
|
+
source: GitConventionSource,
|
|
236
|
+
defaults: GitConventionDefaults = _defaults(),
|
|
237
|
+
): GitConventionReading {
|
|
238
|
+
const layers = source.layers();
|
|
239
|
+
const fallback = defaults[key] ?? null;
|
|
240
|
+
for (const layer of [...layers].reverse().filter((l) => l.carries)) {
|
|
241
|
+
if (layer.parsed === 'malformed') {
|
|
242
|
+
return conventionReading(key, 'malformed', null, layer.path, `${layer.why ?? 'the file cannot be read'}, so the value it may set is unknown`);
|
|
243
|
+
}
|
|
244
|
+
if (layer.shapeError !== undefined) return conventionReading(key, 'invalid', null, layer.path, layer.shapeError);
|
|
245
|
+
const found = _lookup(layer.data, key);
|
|
246
|
+
if (!found.present) continue;
|
|
247
|
+
if ('notAMap' in found) return conventionReading(key, 'invalid', null, layer.path, '`git:` is not a map');
|
|
248
|
+
if (typeof found.value !== 'string') {
|
|
249
|
+
const shown = typeof found.value === 'object' && found.value !== null ? JSON.stringify(found.value) : String(found.value);
|
|
250
|
+
return conventionReading(key, 'invalid', shown, layer.path, `the value is not a string — quote the value, e.g. ${_quoteExample(key)}`);
|
|
251
|
+
}
|
|
252
|
+
const value = found.value;
|
|
253
|
+
const why = invalidReason(key, value);
|
|
254
|
+
return why === null ? conventionReading(key, 'valid', value, layer.path) : conventionReading(key, 'invalid', value, layer.path, why);
|
|
255
|
+
}
|
|
256
|
+
for (const layer of [...layers].reverse().filter((l) => !l.carries && l.parsed === 'valid')) {
|
|
257
|
+
const found = _lookup(layer.data, key);
|
|
258
|
+
if (!found.present || 'notAMap' in found) continue;
|
|
259
|
+
const value = typeof found.value === 'string' ? found.value : String(found.value);
|
|
260
|
+
if (fallback !== null && value === fallback) continue;
|
|
261
|
+
return conventionReading(
|
|
262
|
+
key,
|
|
263
|
+
'discarded',
|
|
264
|
+
value,
|
|
265
|
+
layer.path,
|
|
266
|
+
'user-global files do not carry git.* keys; set it in the project settings file',
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
return conventionReading(key, 'absent', fallback, null);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function readGitConvention(
|
|
273
|
+
source: GitConventionSource,
|
|
274
|
+
defaults: GitConventionDefaults = _defaults(),
|
|
275
|
+
): Record<GitConventionKey, GitConventionReading> {
|
|
276
|
+
const out = {} as Record<GitConventionKey, GitConventionReading>;
|
|
277
|
+
for (const key of GIT_CONVENTION_KEYS) out[key] = readGitConventionKey(key, source, defaults);
|
|
278
|
+
return out;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** Every state a caller must not act on; `show`, `sync` and the `/pr:merge` prose share this one set. */
|
|
282
|
+
export const REFUSAL_STATES: readonly GitConventionState[] = ['malformed', 'invalid', 'discarded', 'unresolvable'];
|
|
283
|
+
|
|
284
|
+
export function isRefusal(state: GitConventionState): boolean {
|
|
285
|
+
return REFUSAL_STATES.includes(state);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** One line naming the reason code, the key and the file. */
|
|
289
|
+
export function describeRefusal(reading: GitConventionReading): string {
|
|
290
|
+
return `${reading.reason ?? 'git-convention-ok'}: git.${reading.key} in ${reading.source ?? '(no file)'} — ${reading.detail ?? reading.state}`;
|
|
291
|
+
}
|