@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
|
@@ -48,8 +48,31 @@
|
|
|
48
48
|
* (external / absolute / out-of-tree targets ignored), the allow rule
|
|
49
49
|
* (same pack · always-installed · declared `requires`), the per-violation text and
|
|
50
50
|
* JSON shapes, the stdout/stderr split, and exit 0 clean / 1 violations.
|
|
51
|
+
* - **ADDED (2026-10-07):** a `scanned: <N>` line on every path (stdout in text
|
|
52
|
+
* mode, stderr under `--format json` so the payload stays parseable), and
|
|
53
|
+
* `--self-test`, which runs this CLI against planted fixture trees. Both are
|
|
54
|
+
* what `src/config/gate-coverage.yml` asks of a gate a pull request runs.
|
|
51
55
|
*
|
|
52
|
-
*
|
|
56
|
+
* THE ADVISORY `suggests` EDGE, AND THE SIBLING GATE THAT REFUSES IT.
|
|
57
|
+
* Since D5 of `road-to-gates-a-pull-request-can-hear` (AI council 2026-10-07)
|
|
58
|
+
* this gate reads `suggests` as PERMITTING a cross-pack link: advisory,
|
|
59
|
+
* non-installing, one-hop, one-way. `lint_rule_skill_pack_reach` states in its
|
|
60
|
+
* own header that `suggests` is deliberately NOT followed. Both are correct,
|
|
61
|
+
* and the discriminator is the direction of the claim:
|
|
62
|
+
*
|
|
63
|
+
* - THAT gate asserts a route WILL RESOLVE. Counting an advisory edge would
|
|
64
|
+
* assert resolution on installs that may not exist.
|
|
65
|
+
* - THIS gate reports a link that MAY DANGLE. An advisory edge is the author
|
|
66
|
+
* stating they accept the dangle for a consumer who declines the companion,
|
|
67
|
+
* so reading it downgrades a finding the author has already answered.
|
|
68
|
+
*
|
|
69
|
+
* The permit is per EDGE, not per link. The council's condition — only
|
|
70
|
+
* safely-degrading links may be permitted — was verified once, by hand, over
|
|
71
|
+
* the 203 links at the 2026-10-09 baseline; nothing re-verifies it for links
|
|
72
|
+
* added later. That is why the permitted COUNT prints on every run including
|
|
73
|
+
* `--quiet`: it is the only standing signal that the set is growing.
|
|
74
|
+
*
|
|
75
|
+
* WHERE THE `requires` GRAPH IS READ FROM.
|
|
53
76
|
*
|
|
54
77
|
* `src/config/discovery/packs.yml` is the source of truth for the pack
|
|
55
78
|
* vocabulary and its `requires` edges — `generate_pack_manifests.ts` DERIVES
|
|
@@ -62,6 +85,7 @@
|
|
|
62
85
|
*/
|
|
63
86
|
|
|
64
87
|
import * as fs from 'node:fs';
|
|
88
|
+
import * as os from 'node:os';
|
|
65
89
|
import * as path from 'node:path';
|
|
66
90
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
67
91
|
import { parse as parseYaml } from 'yaml';
|
|
@@ -74,7 +98,8 @@ import {
|
|
|
74
98
|
iter_artefacts,
|
|
75
99
|
} from './_lib/agent_src.js';
|
|
76
100
|
import { checkRatchet } from './_lib/gate_baseline.js';
|
|
77
|
-
import {
|
|
101
|
+
import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
|
|
102
|
+
import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
|
|
78
103
|
import { parse_frontmatter } from './validate_frontmatter.js';
|
|
79
104
|
|
|
80
105
|
const _HERE = path.resolve(fileURLToPath(import.meta.url));
|
|
@@ -118,6 +143,19 @@ function _set_paths_for_test(opts: { root?: string; vocab?: string }): void {
|
|
|
118
143
|
}
|
|
119
144
|
}
|
|
120
145
|
|
|
146
|
+
// `--self-test` drives this CLI from a CHILD process, which cannot reach the
|
|
147
|
+
// setter above, so the fixture root is also readable from the environment.
|
|
148
|
+
// Applied through the setter rather than at the `ROOT` declaration, so a
|
|
149
|
+
// fixture run is still recognised as overridden and never judged by the
|
|
150
|
+
// repo's violation ratchet.
|
|
151
|
+
// Honoured only inside a self-test child, so an inherited value can never
|
|
152
|
+
// redirect the production gate or switch its ratchet off.
|
|
153
|
+
const _ENV_ROOT =
|
|
154
|
+
process.env['GATE_SELF_TEST_CHILD'] === '1' ? process.env['LINT_PACK_BOUNDARIES_ROOT'] : undefined;
|
|
155
|
+
if (_ENV_ROOT !== undefined && _ENV_ROOT !== '') {
|
|
156
|
+
_set_paths_for_test({ root: _realpath(path.resolve(_ENV_ROOT)) });
|
|
157
|
+
}
|
|
158
|
+
|
|
121
159
|
// [..](target) with an optional #fragment / ?query stripped from the target.
|
|
122
160
|
const LINK_RE = /\[[^\]]*\]\(([^)#?]+)(?:[#?][^)]*)?\)/g;
|
|
123
161
|
|
|
@@ -180,6 +218,35 @@ interface ViolationRecord {
|
|
|
180
218
|
link: string;
|
|
181
219
|
}
|
|
182
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Which edge permits a cross-pack link. `null` is the violation case.
|
|
223
|
+
*
|
|
224
|
+
* `suggests` is the advisory, non-installing edge added for the base-into-
|
|
225
|
+
* narrow class (D5 of `road-to-gates-a-pull-request-can-hear`, AI council
|
|
226
|
+
* 2026-10-07). It is the WEAKEST promise in the list, which is why the ranking
|
|
227
|
+
* below exists: a link that needs it is reported as needing it, never as a
|
|
228
|
+
* `requires` link that happens to also hold.
|
|
229
|
+
*/
|
|
230
|
+
type PermitReason = 'same-pack' | 'always-installed' | 'requires' | 'suggests' | null;
|
|
231
|
+
|
|
232
|
+
/** Strength order — lower is a stronger guarantee that the target is present. */
|
|
233
|
+
const PERMIT_RANK: Record<Exclude<PermitReason, null>, number> = {
|
|
234
|
+
'same-pack': 0,
|
|
235
|
+
'always-installed': 1,
|
|
236
|
+
requires: 2,
|
|
237
|
+
suggests: 3,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/** A link permitted only by `suggests`, kept for the `--show-permitted` report. */
|
|
241
|
+
interface PermittedRecord {
|
|
242
|
+
source_pack: string;
|
|
243
|
+
target_pack: string;
|
|
244
|
+
source: string;
|
|
245
|
+
target: string;
|
|
246
|
+
link: string;
|
|
247
|
+
reason: Exclude<PermitReason, null>;
|
|
248
|
+
}
|
|
249
|
+
|
|
183
250
|
/** Mirror Python `Path.resolve()`: canonicalize existing prefix, append rest. */
|
|
184
251
|
function _realpath(p: string): string {
|
|
185
252
|
try {
|
|
@@ -325,7 +392,36 @@ function _pack_home_dirs(): string[] {
|
|
|
325
392
|
* manifests as an overlay for pack homes the vocabulary does not list.
|
|
326
393
|
*/
|
|
327
394
|
function _pack_requires(): Map<string, string[]> {
|
|
328
|
-
|
|
395
|
+
return _pack_edges().requires;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* `pack id -> direct suggests`.
|
|
400
|
+
*
|
|
401
|
+
* Deliberately NOT expanded: `suggests` is one-hop. Transitive expansion would
|
|
402
|
+
* give the advisory edge the install-forcing reach `requires` has, which is the
|
|
403
|
+
* property the base-into-narrow decision depends on it not having.
|
|
404
|
+
*/
|
|
405
|
+
function _pack_suggests(): Map<string, string[]> {
|
|
406
|
+
return _pack_edges().suggests;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Both edge maps, from ONE read of the vocabulary and one walk of the pack
|
|
411
|
+
* homes.
|
|
412
|
+
*
|
|
413
|
+
* One reader rather than two near-identical ones, so the VOCAB-wins precedence
|
|
414
|
+
* below exists in a single place: two copies would have to be kept in step by
|
|
415
|
+
* hand, and a `requires` map that fell out of step with a `suggests` map read
|
|
416
|
+
* from the same file is a drift nothing reports.
|
|
417
|
+
*
|
|
418
|
+
* NOTE for anyone adding an edge: a `pack.yaml` is only consulted for a pack
|
|
419
|
+
* the vocabulary does not list, so declaring `suggests` there alone has no
|
|
420
|
+
* effect on this gate. `packs.yml` is where an edge has to go.
|
|
421
|
+
*/
|
|
422
|
+
function _pack_edges(): { requires: Map<string, string[]>; suggests: Map<string, string[]> } {
|
|
423
|
+
const requires = new Map<string, string[]>();
|
|
424
|
+
const suggests = new Map<string, string[]>();
|
|
329
425
|
const asList = (v: unknown): string[] => (Array.isArray(v) ? v.map(String) : []);
|
|
330
426
|
|
|
331
427
|
if (_exists(VOCAB)) {
|
|
@@ -335,7 +431,8 @@ function _pack_requires(): Map<string, string[]> {
|
|
|
335
431
|
if (entry !== null && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
336
432
|
const e = entry as Record<string, unknown>;
|
|
337
433
|
if (typeof e['id'] === 'string') {
|
|
338
|
-
|
|
434
|
+
requires.set(e['id'], asList(e['requires']));
|
|
435
|
+
suggests.set(e['id'], asList(e['suggests']));
|
|
339
436
|
}
|
|
340
437
|
}
|
|
341
438
|
}
|
|
@@ -344,11 +441,12 @@ function _pack_requires(): Map<string, string[]> {
|
|
|
344
441
|
for (const dir of _pack_home_dirs()) {
|
|
345
442
|
const meta = _load_pack_meta(dir);
|
|
346
443
|
const id = typeof meta['id'] === 'string' ? meta['id'] : path.basename(dir);
|
|
347
|
-
if (!
|
|
348
|
-
|
|
444
|
+
if (!requires.has(id)) {
|
|
445
|
+
requires.set(id, asList(meta['requires']));
|
|
446
|
+
suggests.set(id, asList(meta['suggests']));
|
|
349
447
|
}
|
|
350
448
|
}
|
|
351
|
-
return
|
|
449
|
+
return { requires, suggests };
|
|
352
450
|
}
|
|
353
451
|
|
|
354
452
|
/** Transitive expansion of `requires`, cycle-safe. */
|
|
@@ -529,19 +627,45 @@ function _scan_file(p: string): string[] {
|
|
|
529
627
|
return out;
|
|
530
628
|
}
|
|
531
629
|
|
|
532
|
-
|
|
630
|
+
/**
|
|
631
|
+
* Which edge, if any, lets a link out of `source_pack` reach `target_pack`.
|
|
632
|
+
*
|
|
633
|
+
* `null` is the violation case. The reason is returned rather than a bare
|
|
634
|
+
* boolean because `suggests` is advisory: a reader who sees a permitted
|
|
635
|
+
* base-into-narrow link needs to know it was permitted by an edge that does
|
|
636
|
+
* NOT install the target, which is a different promise from `requires`.
|
|
637
|
+
*/
|
|
638
|
+
function _permit_reason(
|
|
533
639
|
source_pack: string,
|
|
534
640
|
target_pack: string,
|
|
535
641
|
requires: string[],
|
|
536
642
|
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
537
|
-
|
|
643
|
+
suggests: readonly string[] = [],
|
|
644
|
+
): PermitReason {
|
|
538
645
|
if (source_pack === target_pack) {
|
|
539
|
-
return
|
|
646
|
+
return 'same-pack';
|
|
540
647
|
}
|
|
541
648
|
if (always_installed.has(target_pack)) {
|
|
542
|
-
return
|
|
649
|
+
return 'always-installed';
|
|
650
|
+
}
|
|
651
|
+
if ((requires || []).includes(target_pack)) {
|
|
652
|
+
return 'requires';
|
|
543
653
|
}
|
|
544
|
-
|
|
654
|
+
// One-hop and one-way by construction: the caller passes the SOURCE pack's
|
|
655
|
+
// own direct `suggests` list, never a closure over it. A transitive
|
|
656
|
+
// advisory edge would re-create the install-forcing reach `requires` has,
|
|
657
|
+
// which is the property this edge exists not to have.
|
|
658
|
+
return suggests.includes(target_pack) ? 'suggests' : null;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function _is_allowed(
|
|
662
|
+
source_pack: string,
|
|
663
|
+
target_pack: string,
|
|
664
|
+
requires: string[],
|
|
665
|
+
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
666
|
+
suggests: readonly string[] = [],
|
|
667
|
+
): boolean {
|
|
668
|
+
return _permit_reason(source_pack, target_pack, requires, always_installed, suggests) !== null;
|
|
545
669
|
}
|
|
546
670
|
|
|
547
671
|
/**
|
|
@@ -557,11 +681,47 @@ function _link_allowed(
|
|
|
557
681
|
target_packs: readonly string[],
|
|
558
682
|
closureOf: (pack: string) => Set<string>,
|
|
559
683
|
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
684
|
+
suggestsOf: (pack: string) => readonly string[] = () => [],
|
|
560
685
|
): boolean {
|
|
561
|
-
return
|
|
686
|
+
return (
|
|
687
|
+
_link_permit_reason(source_packs, target_packs, closureOf, always_installed, suggestsOf) !==
|
|
688
|
+
null
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* The weakest edge the link relies on, or `null` when nothing permits it.
|
|
694
|
+
*
|
|
695
|
+
* Weakest, not first: a link permitted for one source pack by `requires` and
|
|
696
|
+
* for another only by `suggests` is reported as `suggests`, because that is
|
|
697
|
+
* the promise a consumer actually gets.
|
|
698
|
+
*/
|
|
699
|
+
function _link_permit_reason(
|
|
700
|
+
source_packs: readonly string[],
|
|
701
|
+
target_packs: readonly string[],
|
|
702
|
+
closureOf: (pack: string) => Set<string>,
|
|
703
|
+
always_installed: ReadonlySet<string> = new Set([ALWAYS_INSTALLED]),
|
|
704
|
+
suggestsOf: (pack: string) => readonly string[] = () => [],
|
|
705
|
+
): PermitReason {
|
|
706
|
+
let weakest: PermitReason = 'same-pack';
|
|
707
|
+
for (const s of source_packs) {
|
|
562
708
|
const reach = [...closureOf(s)];
|
|
563
|
-
|
|
564
|
-
|
|
709
|
+
const sug = suggestsOf(s);
|
|
710
|
+
let best: PermitReason = null;
|
|
711
|
+
for (const t of target_packs) {
|
|
712
|
+
const r = _permit_reason(s, t, reach, always_installed, sug);
|
|
713
|
+
if (r !== null && (best === null || PERMIT_RANK[r] < PERMIT_RANK[best])) {
|
|
714
|
+
best = r;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
if (best === null) {
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
if (PERMIT_RANK[best] > PERMIT_RANK[weakest]) {
|
|
721
|
+
weakest = best;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return weakest;
|
|
565
725
|
}
|
|
566
726
|
|
|
567
727
|
/** Mirror Python `json.dump(obj, indent=2)` with `ensure_ascii=True`. */
|
|
@@ -584,11 +744,14 @@ function _json_dumps_ascii(obj: unknown): string {
|
|
|
584
744
|
interface ParsedArgs {
|
|
585
745
|
format: 'text' | 'json';
|
|
586
746
|
quiet: boolean;
|
|
747
|
+
/** List the links permitted only by an advisory `suggests` edge. */
|
|
748
|
+
show_permitted: boolean;
|
|
587
749
|
}
|
|
588
750
|
|
|
589
751
|
function parse_args(argv: readonly string[]): ParsedArgs {
|
|
590
752
|
let format: 'text' | 'json' = 'text';
|
|
591
753
|
let quiet = false;
|
|
754
|
+
let show_permitted = false;
|
|
592
755
|
for (let i = 0; i < argv.length; i++) {
|
|
593
756
|
const arg = argv[i] as string;
|
|
594
757
|
if (arg === '--format') {
|
|
@@ -612,16 +775,19 @@ function parse_args(argv: readonly string[]): ParsedArgs {
|
|
|
612
775
|
format = v;
|
|
613
776
|
} else if (arg === '--quiet') {
|
|
614
777
|
quiet = true;
|
|
778
|
+
} else if (arg === '--show-permitted') {
|
|
779
|
+
show_permitted = true;
|
|
615
780
|
} else if (arg === '-h' || arg === '--help') {
|
|
616
781
|
process.stdout.write(
|
|
617
|
-
'usage: lint_pack_boundaries [-h] [--format {text,json}] [--quiet]
|
|
782
|
+
'usage: lint_pack_boundaries [-h] [--format {text,json}] [--quiet] ' +
|
|
783
|
+
'[--show-permitted] [--self-test]\n',
|
|
618
784
|
);
|
|
619
785
|
process.exit(0);
|
|
620
786
|
} else {
|
|
621
787
|
_argparse_error(`unrecognized arguments: ${arg}`);
|
|
622
788
|
}
|
|
623
789
|
}
|
|
624
|
-
return { format, quiet };
|
|
790
|
+
return { format, quiet, show_permitted };
|
|
625
791
|
}
|
|
626
792
|
|
|
627
793
|
function _argparse_error(message: string): never {
|
|
@@ -629,8 +795,161 @@ function _argparse_error(message: string): never {
|
|
|
629
795
|
process.exit(2);
|
|
630
796
|
}
|
|
631
797
|
|
|
798
|
+
/**
|
|
799
|
+
* Plant fixture trees and run this gate's real CLI against each one.
|
|
800
|
+
*
|
|
801
|
+
* Three rejecting cases cover the three exits a pull request can be failed by:
|
|
802
|
+
* an undeclared cross-pack link, an artefact with no resolvable pack, and an
|
|
803
|
+
* empty corpus. The two accepting cases pin the allow rule from the other side,
|
|
804
|
+
* so a gate that started rejecting everything fails here too.
|
|
805
|
+
*/
|
|
806
|
+
function selfTest(): number {
|
|
807
|
+
const plant = (name: string, files: Record<string, string>): string => {
|
|
808
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), `lpb-selftest-${name}-`));
|
|
809
|
+
for (const [rel, body] of Object.entries(files)) {
|
|
810
|
+
const p = path.join(dir, rel);
|
|
811
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
812
|
+
fs.writeFileSync(p, body, 'utf-8');
|
|
813
|
+
}
|
|
814
|
+
return dir;
|
|
815
|
+
};
|
|
816
|
+
const skill = (slug: string, packs: string, body: string): [string, string] => [
|
|
817
|
+
`skills/${slug}/SKILL.md`,
|
|
818
|
+
`---\nname: ${slug}\npacks: [${packs}]\n---\n\n${body}\n`,
|
|
819
|
+
];
|
|
820
|
+
const run = (dir: string): number => {
|
|
821
|
+
const prev = process.env['LINT_PACK_BOUNDARIES_ROOT'];
|
|
822
|
+
process.env['LINT_PACK_BOUNDARIES_ROOT'] = dir;
|
|
823
|
+
try {
|
|
824
|
+
return runGateCli(
|
|
825
|
+
_DEFAULT_ROOT,
|
|
826
|
+
path.join('src', 'scripts', 'lint_pack_boundaries.ts'),
|
|
827
|
+
['--quiet'],
|
|
828
|
+
_DEFAULT_ROOT,
|
|
829
|
+
);
|
|
830
|
+
} finally {
|
|
831
|
+
if (prev === undefined) {
|
|
832
|
+
delete process.env['LINT_PACK_BOUNDARIES_ROOT'];
|
|
833
|
+
} else {
|
|
834
|
+
process.env['LINT_PACK_BOUNDARIES_ROOT'] = prev;
|
|
835
|
+
}
|
|
836
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
const twoPacks = '- id: alpha\n requires: []\n- id: beta\n requires: []\n';
|
|
840
|
+
// A reject case counts only on the exit it names: a crash or a dead-scope
|
|
841
|
+
// exit on a fixture that should yield a finding reads as NOT rejected.
|
|
842
|
+
const rejectsWith = (want: number, got: number): number => (got === want ? 1 : 0);
|
|
843
|
+
|
|
844
|
+
return runSelfTest({
|
|
845
|
+
gate: 'lint_pack_boundaries',
|
|
846
|
+
minCases: 7,
|
|
847
|
+
minRejectCases: 4,
|
|
848
|
+
cases: [
|
|
849
|
+
{
|
|
850
|
+
name: 'an undeclared cross-pack link is rejected with exit 1',
|
|
851
|
+
expect: 'reject',
|
|
852
|
+
run: () =>
|
|
853
|
+
rejectsWith(1, run(
|
|
854
|
+
plant('cross', {
|
|
855
|
+
'packs.yml': twoPacks,
|
|
856
|
+
...Object.fromEntries([
|
|
857
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
858
|
+
skill('b-one', 'beta', 'leaf'),
|
|
859
|
+
]),
|
|
860
|
+
}),
|
|
861
|
+
)),
|
|
862
|
+
},
|
|
863
|
+
{
|
|
864
|
+
name: 'a SKILL.md with no packs is a finding (exit 1), never a silent pass',
|
|
865
|
+
expect: 'reject',
|
|
866
|
+
run: () =>
|
|
867
|
+
rejectsWith(1, run(
|
|
868
|
+
plant('nopack', {
|
|
869
|
+
'packs.yml': twoPacks,
|
|
870
|
+
'skills/nopack/SKILL.md': '---\nname: nopack\n---\n\nno packs key\n',
|
|
871
|
+
}),
|
|
872
|
+
)),
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
name: 'an empty corpus is a dead scope (exit 2), not "no cross-pack drift"',
|
|
876
|
+
expect: 'reject',
|
|
877
|
+
run: () => rejectsWith(2, run(plant('empty', { 'packs.yml': twoPacks }))),
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
name: 'a link declared through requires passes',
|
|
881
|
+
expect: 'accept',
|
|
882
|
+
run: () =>
|
|
883
|
+
run(
|
|
884
|
+
plant('declared', {
|
|
885
|
+
'packs.yml': '- id: alpha\n requires: [beta]\n- id: beta\n requires: []\n',
|
|
886
|
+
...Object.fromEntries([
|
|
887
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
888
|
+
skill('b-one', 'beta', 'leaf'),
|
|
889
|
+
]),
|
|
890
|
+
}),
|
|
891
|
+
),
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
name: 'a link inside one pack passes',
|
|
895
|
+
expect: 'accept',
|
|
896
|
+
run: () =>
|
|
897
|
+
run(
|
|
898
|
+
plant('same', {
|
|
899
|
+
'packs.yml': twoPacks,
|
|
900
|
+
...Object.fromEntries([
|
|
901
|
+
skill('a-one', 'alpha', 'reaches [two](../a-two/SKILL.md)'),
|
|
902
|
+
skill('a-two', 'alpha', 'leaf'),
|
|
903
|
+
]),
|
|
904
|
+
}),
|
|
905
|
+
),
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
name: 'a link an advisory `suggests` edge permits passes',
|
|
909
|
+
expect: 'accept',
|
|
910
|
+
run: () =>
|
|
911
|
+
run(
|
|
912
|
+
plant('suggests-permit', {
|
|
913
|
+
'packs.yml':
|
|
914
|
+
'- id: alpha\n requires: []\n suggests: [beta]\n' +
|
|
915
|
+
'- id: beta\n requires: []\n',
|
|
916
|
+
...Object.fromEntries([
|
|
917
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
918
|
+
skill('b-one', 'beta', 'leaf'),
|
|
919
|
+
]),
|
|
920
|
+
}),
|
|
921
|
+
),
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
// The denial half. Without it the case above cannot tell a
|
|
925
|
+
// working permit from a gate that stopped reporting at all.
|
|
926
|
+
name: 'the same link without the `suggests` edge is still rejected with exit 1',
|
|
927
|
+
expect: 'reject',
|
|
928
|
+
run: () =>
|
|
929
|
+
rejectsWith(1, run(
|
|
930
|
+
plant('suggests-absent', {
|
|
931
|
+
'packs.yml': twoPacks,
|
|
932
|
+
...Object.fromEntries([
|
|
933
|
+
skill('a-one', 'alpha', 'reaches [b](../b-one/SKILL.md)'),
|
|
934
|
+
skill('b-one', 'beta', 'leaf'),
|
|
935
|
+
]),
|
|
936
|
+
}),
|
|
937
|
+
)),
|
|
938
|
+
},
|
|
939
|
+
],
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
|
|
632
943
|
function main(argv?: readonly string[]): number {
|
|
633
|
-
const
|
|
944
|
+
const rawArgv = argv ?? process.argv.slice(2);
|
|
945
|
+
if (rawArgv.includes('--self-test')) {
|
|
946
|
+
if (process.env['GATE_SELF_TEST_CHILD'] === '1') {
|
|
947
|
+
process.stderr.write('lint_pack_boundaries: --self-test does not recurse\n');
|
|
948
|
+
return 2;
|
|
949
|
+
}
|
|
950
|
+
return selfTest();
|
|
951
|
+
}
|
|
952
|
+
const args = parse_args(rawArgv);
|
|
634
953
|
|
|
635
954
|
const { index: artefact_pack, unassigned, scanned } = _build_artefact_index();
|
|
636
955
|
|
|
@@ -638,12 +957,17 @@ function main(argv?: readonly string[]): number {
|
|
|
638
957
|
// clean. That was this gate's shipped state until 2026-08-02 — it walked
|
|
639
958
|
// the deleted `packages/` tree and skipped green forever.
|
|
640
959
|
try {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
960
|
+
reportScanned(
|
|
961
|
+
{
|
|
962
|
+
gate: 'lint_pack_boundaries',
|
|
963
|
+
scanned,
|
|
964
|
+
units: 'artefact(s)',
|
|
965
|
+
roots: _scan_roots().map((r) => _relPosix(r, ROOT) || '.'),
|
|
966
|
+
},
|
|
967
|
+
args.format === 'json'
|
|
968
|
+
? process.stderr.write.bind(process.stderr)
|
|
969
|
+
: process.stdout.write.bind(process.stdout),
|
|
970
|
+
);
|
|
647
971
|
} catch (exc) {
|
|
648
972
|
if (!(exc instanceof DeadScopeError)) {
|
|
649
973
|
throw exc;
|
|
@@ -652,7 +976,8 @@ function main(argv?: readonly string[]): number {
|
|
|
652
976
|
return 2;
|
|
653
977
|
}
|
|
654
978
|
|
|
655
|
-
const pack_requires =
|
|
979
|
+
const { requires: pack_requires, suggests: pack_suggests } = _pack_edges();
|
|
980
|
+
const suggestsOf = (pack: string): readonly string[] => pack_suggests.get(pack) ?? [];
|
|
656
981
|
const always_installed = _always_installed_packs();
|
|
657
982
|
const closureCache = new Map<string, Set<string>>();
|
|
658
983
|
const closureOf = (pack: string): Set<string> => {
|
|
@@ -665,6 +990,7 @@ function main(argv?: readonly string[]): number {
|
|
|
665
990
|
};
|
|
666
991
|
|
|
667
992
|
const violations: ViolationRecord[] = [];
|
|
993
|
+
const permitted: PermittedRecord[] = [];
|
|
668
994
|
|
|
669
995
|
// Fail-safe: a unit-defining artefact with no resolvable pack cannot be
|
|
670
996
|
// boundary-checked, so it is a finding rather than a silent exclusion.
|
|
@@ -692,7 +1018,27 @@ function main(argv?: readonly string[]): number {
|
|
|
692
1018
|
if (target_packs === undefined) {
|
|
693
1019
|
continue; // docs/, scripts/, root files, unassigned — not pack-scoped
|
|
694
1020
|
}
|
|
695
|
-
|
|
1021
|
+
const reason = _link_permit_reason(
|
|
1022
|
+
src_packs,
|
|
1023
|
+
target_packs,
|
|
1024
|
+
closureOf,
|
|
1025
|
+
always_installed,
|
|
1026
|
+
suggestsOf,
|
|
1027
|
+
);
|
|
1028
|
+
if (reason !== null) {
|
|
1029
|
+
// Only the advisory edge is worth reporting: the other three
|
|
1030
|
+
// mean the target is installed, so there is nothing a reader
|
|
1031
|
+
// has to weigh.
|
|
1032
|
+
if (reason === 'suggests') {
|
|
1033
|
+
permitted.push({
|
|
1034
|
+
source_pack: src_packs.join('+'),
|
|
1035
|
+
target_pack: target_packs.join('+'),
|
|
1036
|
+
source: rel_path,
|
|
1037
|
+
target: target_rel,
|
|
1038
|
+
link: raw,
|
|
1039
|
+
reason,
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
696
1042
|
continue;
|
|
697
1043
|
}
|
|
698
1044
|
violations.push({
|
|
@@ -722,6 +1068,7 @@ function main(argv?: readonly string[]): number {
|
|
|
722
1068
|
count: violations.length,
|
|
723
1069
|
scanned,
|
|
724
1070
|
unassigned: unassigned.length,
|
|
1071
|
+
permitted_by_suggests: permitted,
|
|
725
1072
|
ratchet:
|
|
726
1073
|
verdict === null ? null : { status: verdict.status, baseline: verdict.baseline },
|
|
727
1074
|
}) + '\n',
|
|
@@ -735,6 +1082,32 @@ function main(argv?: readonly string[]): number {
|
|
|
735
1082
|
`${pack_requires.size} packs (${unassigned.length} outside pack scope)\n`,
|
|
736
1083
|
);
|
|
737
1084
|
}
|
|
1085
|
+
// Two different questions, so two different defaults.
|
|
1086
|
+
//
|
|
1087
|
+
// HOW MANY links an advisory edge is carrying prints on EVERY run,
|
|
1088
|
+
// `--quiet` included. The permit is granted per EDGE, not per link: once an
|
|
1089
|
+
// edge is declared, every future link on it is permitted without anyone
|
|
1090
|
+
// re-checking that it degrades safely. An adversarial review demonstrated
|
|
1091
|
+
// that by planting a link on a declared edge and watching this gate exit 0
|
|
1092
|
+
// where it would previously have failed the pull request. `--quiet` is what
|
|
1093
|
+
// CI passes, so a count visible only without it would miss the one log that
|
|
1094
|
+
// matters.
|
|
1095
|
+
//
|
|
1096
|
+
// WHICH links they are stays behind `--show-permitted`. A permit is not a
|
|
1097
|
+
// finding, and printing dozens of lines beside the violations reads as one.
|
|
1098
|
+
process.stdout.write(
|
|
1099
|
+
`${permitted.length} link(s) permitted by an advisory \`suggests\` edge` +
|
|
1100
|
+
(args.show_permitted ? '' : ' (--show-permitted lists them)') +
|
|
1101
|
+
'\n',
|
|
1102
|
+
);
|
|
1103
|
+
if (args.show_permitted) {
|
|
1104
|
+
for (const p of permitted) {
|
|
1105
|
+
process.stdout.write(
|
|
1106
|
+
` ~ ${p.source_pack} -> ${p.target_pack} : ${p.source} \u2192 ${p.target} ` +
|
|
1107
|
+
`(link: ${p.link}) — permitted by \`${p.reason}\`\n`,
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
738
1111
|
for (const v of violations) {
|
|
739
1112
|
if (v.kind === 'unresolved-pack') {
|
|
740
1113
|
process.stdout.write(
|
|
@@ -750,8 +1123,8 @@ function main(argv?: readonly string[]): number {
|
|
|
750
1123
|
}
|
|
751
1124
|
if (violations.length > 0) {
|
|
752
1125
|
process.stdout.write(
|
|
753
|
-
`\n${violations.length} cross-pack violation(s) — declare 'requires'
|
|
754
|
-
'
|
|
1126
|
+
`\n${violations.length} cross-pack violation(s) — declare 'requires' or an ` +
|
|
1127
|
+
"advisory 'suggests' edge in packs.yml, or move the artefact\n",
|
|
755
1128
|
);
|
|
756
1129
|
if (verdict !== null) {
|
|
757
1130
|
if (verdict.ok) {
|
|
@@ -801,9 +1174,14 @@ export {
|
|
|
801
1174
|
_resolve_link,
|
|
802
1175
|
_scan_file,
|
|
803
1176
|
_always_installed_packs,
|
|
1177
|
+
type PermitReason,
|
|
804
1178
|
_is_allowed,
|
|
805
1179
|
_link_allowed,
|
|
1180
|
+
_link_permit_reason,
|
|
1181
|
+
_pack_suggests,
|
|
1182
|
+
_permit_reason,
|
|
806
1183
|
_load_pack_meta,
|
|
1184
|
+
_pack_edges,
|
|
807
1185
|
_pack_requires,
|
|
808
1186
|
_requires_closure,
|
|
809
1187
|
_packs_of,
|