@event4u/agent-config 5.2.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-src/commands/agent-handoff.md +1 -9
- package/.agent-src/commands/agent-status.md +1 -9
- package/.agent-src/commands/agents/audit.md +1 -9
- package/.agent-src/commands/agents/init.md +1 -9
- package/.agent-src/commands/agents/optimize.md +1 -9
- package/.agent-src/commands/agents/user/accept.md +1 -9
- package/.agent-src/commands/agents/user/init.md +1 -9
- package/.agent-src/commands/agents/user/review.md +1 -9
- package/.agent-src/commands/agents/user/show.md +1 -9
- package/.agent-src/commands/agents/user/update.md +1 -9
- package/.agent-src/commands/agents/user.md +1 -9
- package/.agent-src/commands/agents.md +1 -9
- package/.agent-src/commands/analytics/prune.md +1 -9
- package/.agent-src/commands/analytics/show.md +1 -9
- package/.agent-src/commands/analytics.md +1 -9
- package/.agent-src/commands/analyze-reference-repo.md +1 -9
- package/.agent-src/commands/bug-fix.md +1 -9
- package/.agent-src/commands/bug-investigate.md +1 -9
- package/.agent-src/commands/challenge-me/vision.md +1 -9
- package/.agent-src/commands/challenge-me/with-docs.md +1 -9
- package/.agent-src/commands/challenge-me.md +1 -9
- package/.agent-src/commands/chat-history/import.md +1 -9
- package/.agent-src/commands/chat-history/learn.md +1 -9
- package/.agent-src/commands/chat-history/show.md +1 -9
- package/.agent-src/commands/chat-history.md +1 -9
- package/.agent-src/commands/check-current-md.md +1 -9
- package/.agent-src/commands/commit/in-chunks.md +1 -9
- package/.agent-src/commands/commit.md +1 -9
- package/.agent-src/commands/condense.md +1 -9
- package/.agent-src/commands/context/create.md +1 -9
- package/.agent-src/commands/context/refactor.md +1 -9
- package/.agent-src/commands/context.md +1 -9
- package/.agent-src/commands/cost-report.md +1 -9
- package/.agent-src/commands/council/analysis.md +1 -9
- package/.agent-src/commands/council/debate.md +1 -9
- package/.agent-src/commands/council/default.md +1 -9
- package/.agent-src/commands/council/design.md +1 -9
- package/.agent-src/commands/council/optimize.md +1 -9
- package/.agent-src/commands/council/pr.md +1 -9
- package/.agent-src/commands/council.md +1 -9
- package/.agent-src/commands/create-pr/description-only.md +1 -9
- package/.agent-src/commands/create-pr.md +1 -9
- package/.agent-src/commands/e2e-heal.md +1 -9
- package/.agent-src/commands/e2e-plan.md +1 -9
- package/.agent-src/commands/estimate-ticket.md +1 -9
- package/.agent-src/commands/feature/dev.md +1 -9
- package/.agent-src/commands/feature/explore.md +1 -9
- package/.agent-src/commands/feature/plan.md +1 -9
- package/.agent-src/commands/feature/refactor.md +1 -9
- package/.agent-src/commands/feature/roadmap.md +1 -9
- package/.agent-src/commands/feature.md +1 -9
- package/.agent-src/commands/fix/ci.md +1 -9
- package/.agent-src/commands/fix/portability.md +1 -9
- package/.agent-src/commands/fix/pr-bot-comments.md +1 -9
- package/.agent-src/commands/fix/pr-comments.md +1 -9
- package/.agent-src/commands/fix/pr-developer-comments.md +1 -9
- package/.agent-src/commands/fix/refs.md +1 -9
- package/.agent-src/commands/fix/seeder.md +1 -9
- package/.agent-src/commands/fix.md +1 -9
- package/.agent-src/commands/ghostwriter/delete.md +1 -9
- package/.agent-src/commands/ghostwriter/fetch.md +1 -9
- package/.agent-src/commands/ghostwriter/list.md +1 -9
- package/.agent-src/commands/ghostwriter/show.md +1 -9
- package/.agent-src/commands/ghostwriter/write.md +1 -9
- package/.agent-src/commands/ghostwriter.md +1 -9
- package/.agent-src/commands/grill-me.md +1 -9
- package/.agent-src/commands/implement-ticket.md +1 -9
- package/.agent-src/commands/jira-ticket.md +1 -9
- package/.agent-src/commands/judge/on-diff.md +1 -9
- package/.agent-src/commands/judge/solo.md +1 -9
- package/.agent-src/commands/judge/steps.md +1 -9
- package/.agent-src/commands/judge.md +1 -9
- package/.agent-src/commands/knowledge/forget.md +1 -9
- package/.agent-src/commands/knowledge/ingest.md +1 -9
- package/.agent-src/commands/knowledge/list.md +1 -9
- package/.agent-src/commands/knowledge.md +1 -9
- package/.agent-src/commands/memory/add.md +1 -9
- package/.agent-src/commands/memory/learn-low-impact.md +1 -9
- package/.agent-src/commands/memory/load.md +1 -9
- package/.agent-src/commands/memory/mine-session.md +1 -9
- package/.agent-src/commands/memory/promote.md +1 -9
- package/.agent-src/commands/memory/propose.md +1 -9
- package/.agent-src/commands/memory.md +1 -9
- package/.agent-src/commands/mode.md +1 -9
- package/.agent-src/commands/module/create.md +1 -9
- package/.agent-src/commands/module/explore.md +1 -9
- package/.agent-src/commands/module.md +1 -9
- package/.agent-src/commands/optimize/agents-dir.md +1 -9
- package/.agent-src/commands/optimize/augmentignore.md +1 -9
- package/.agent-src/commands/optimize/rtk.md +1 -9
- package/.agent-src/commands/optimize/skills.md +1 -9
- package/.agent-src/commands/optimize-prompt.md +1 -9
- package/.agent-src/commands/optimize.md +1 -9
- package/.agent-src/commands/orchestrate.md +1 -9
- package/.agent-src/commands/override/create.md +1 -9
- package/.agent-src/commands/override/manage.md +1 -9
- package/.agent-src/commands/override.md +1 -9
- package/.agent-src/commands/package-reset.md +1 -9
- package/.agent-src/commands/package-test.md +1 -9
- package/.agent-src/commands/post-as/ghostwriter.md +1 -9
- package/.agent-src/commands/post-as/me.md +1 -9
- package/.agent-src/commands/post-as.md +1 -9
- package/.agent-src/commands/prepare-for-review.md +1 -9
- package/.agent-src/commands/project-analyze.md +1 -9
- package/.agent-src/commands/project-health.md +1 -9
- package/.agent-src/commands/quality-fix.md +1 -9
- package/.agent-src/commands/refine-ticket.md +1 -9
- package/.agent-src/commands/research/deep.md +1 -9
- package/.agent-src/commands/research/report.md +1 -9
- package/.agent-src/commands/research.md +1 -9
- package/.agent-src/commands/review-changes.md +1 -9
- package/.agent-src/commands/review-routing.md +1 -9
- package/.agent-src/commands/roadmap/ai-council.md +1 -9
- package/.agent-src/commands/roadmap/create.md +1 -9
- package/.agent-src/commands/roadmap/process-full.md +1 -9
- package/.agent-src/commands/roadmap/process-phase.md +1 -9
- package/.agent-src/commands/roadmap/process-step.md +1 -9
- package/.agent-src/commands/roadmap.md +1 -9
- package/.agent-src/commands/rule-compliance-audit.md +1 -9
- package/.agent-src/commands/set-cost-profile.md +1 -9
- package/.agent-src/commands/sync-agent-settings.md +1 -9
- package/.agent-src/commands/sync-gitignore/fix.md +1 -9
- package/.agent-src/commands/sync-gitignore.md +1 -9
- package/.agent-src/commands/tests/create.md +1 -9
- package/.agent-src/commands/tests/execute.md +1 -9
- package/.agent-src/commands/tests.md +1 -9
- package/.agent-src/commands/threat-model.md +1 -9
- package/.agent-src/commands/update-form-request-messages.md +1 -9
- package/.agent-src/commands/upstream-contribute.md +1 -9
- package/.agent-src/commands/video/from-script.md +1 -9
- package/.agent-src/commands/video/scene.md +1 -9
- package/.agent-src/commands/video/stitch.md +1 -9
- package/.agent-src/commands/video/storyboard.md +1 -9
- package/.agent-src/commands/video.md +1 -9
- package/.agent-src/commands/work.md +1 -9
- package/.agent-src/contexts/model-recommendations.md +82 -82
- package/.agent-src/personas/ai-agent.md +0 -2
- package/.agent-src/personas/ai-video-technical-director.md +0 -2
- package/.agent-src/personas/backend-architect.md +0 -2
- package/.agent-src/personas/cmo.md +0 -2
- package/.agent-src/personas/critical-challenger.md +0 -2
- package/.agent-src/personas/customer-success-lead.md +0 -2
- package/.agent-src/personas/developer.md +0 -2
- package/.agent-src/personas/discovery-lead.md +0 -2
- package/.agent-src/personas/eloquent-tamer.md +0 -2
- package/.agent-src/personas/engineering-manager.md +0 -2
- package/.agent-src/personas/finance-partner.md +0 -2
- package/.agent-src/personas/frontend-engineer.md +0 -2
- package/.agent-src/personas/growth-pm.md +0 -2
- package/.agent-src/personas/hollywood-director.md +0 -2
- package/.agent-src/personas/people-strategist.md +0 -2
- package/.agent-src/personas/product-owner.md +0 -1
- package/.agent-src/personas/qa.md +0 -2
- package/.agent-src/personas/revops-maintainer.md +0 -2
- package/.agent-src/personas/revops.md +0 -2
- package/.agent-src/personas/security-engineer.md +0 -2
- package/.agent-src/personas/senior-engineer.md +0 -2
- package/.agent-src/personas/stakeholder.md +0 -2
- package/.agent-src/personas/strategist.md +0 -2
- package/.agent-src/personas/tech-writer.md +0 -2
- package/.agent-src/rules/agent-authority.md +0 -9
- package/.agent-src/rules/analysis-skill-routing.md +0 -9
- package/.agent-src/rules/architecture.md +0 -9
- package/.agent-src/rules/artifact-drafting-protocol.md +0 -9
- package/.agent-src/rules/artifact-engagement-recording.md +0 -9
- package/.agent-src/rules/ask-when-uncertain.md +0 -9
- package/.agent-src/rules/augment-edit-discipline.md +0 -9
- package/.agent-src/rules/augment-source-of-truth.md +0 -9
- package/.agent-src/rules/autonomous-execution.md +0 -9
- package/.agent-src/rules/cli-output-handling.md +0 -9
- package/.agent-src/rules/command-suggestion-policy.md +0 -9
- package/.agent-src/rules/commit-conventions.md +0 -9
- package/.agent-src/rules/commit-policy.md +0 -9
- package/.agent-src/rules/context-hygiene.md +0 -9
- package/.agent-src/rules/copilot-routing.md +0 -9
- package/.agent-src/rules/devcontainer-routing.md +0 -9
- package/.agent-src/rules/direct-answers.md +0 -9
- package/.agent-src/rules/docker-commands.md +0 -9
- package/.agent-src/rules/domain-adoption-policy.md +0 -9
- package/.agent-src/rules/domain-safety-disclaimer.md +0 -9
- package/.agent-src/rules/domain-safety-pii.md +0 -9
- package/.agent-src/rules/domain-safety-retention.md +0 -9
- package/.agent-src/rules/downstream-changes.md +0 -9
- package/.agent-src/rules/engineering-safety-floor.md +0 -9
- package/.agent-src/rules/external-reference-deep-dive.md +0 -9
- package/.agent-src/rules/fast-path-marker-visibility.md +0 -9
- package/.agent-src/rules/finance-safety-floor.md +0 -6
- package/.agent-src/rules/framework-neutrality-in-generic-skills.md +0 -9
- package/.agent-src/rules/git-history-discipline.md +0 -9
- package/.agent-src/rules/guidelines.md +0 -9
- package/.agent-src/rules/improve-before-implement.md +0 -9
- package/.agent-src/rules/invite-challenge.md +0 -9
- package/.agent-src/rules/language-and-tone.md +0 -9
- package/.agent-src/rules/laravel-routing.md +0 -4
- package/.agent-src/rules/laravel-translations.md +0 -4
- package/.agent-src/rules/linked-projects-onboarding-gate.md +0 -3
- package/.agent-src/rules/low-impact-corpus-privacy-floor.md +0 -9
- package/.agent-src/rules/markdown-safe-codeblocks.md +0 -9
- package/.agent-src/rules/media-governance-routing.md +0 -9
- package/.agent-src/rules/minimal-safe-diff.md +0 -9
- package/.agent-src/rules/missing-tool-handling.md +0 -9
- package/.agent-src/rules/model-recommendation.md +69 -15
- package/.agent-src/rules/no-attribution-footers.md +0 -9
- package/.agent-src/rules/no-cheap-questions.md +0 -9
- package/.agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -9
- package/.agent-src/rules/no-pr-progress-comments.md +0 -9
- package/.agent-src/rules/no-roadmap-references.md +0 -9
- package/.agent-src/rules/non-destructive-by-default.md +0 -9
- package/.agent-src/rules/onboarding-gate.md +0 -9
- package/.agent-src/rules/package-ci-checks.md +0 -9
- package/.agent-src/rules/persona-governance.md +0 -9
- package/.agent-src/rules/php-coding.md +0 -4
- package/.agent-src/rules/preservation-guard.md +0 -9
- package/.agent-src/rules/provider-lifecycle-discipline.md +0 -9
- package/.agent-src/rules/reviewer-awareness.md +0 -9
- package/.agent-src/rules/roadmap-ci-steps-policy.md +0 -9
- package/.agent-src/rules/roadmap-progress-sync.md +0 -9
- package/.agent-src/rules/role-mode-adherence.md +0 -9
- package/.agent-src/rules/rule-type-governance.md +0 -9
- package/.agent-src/rules/runtime-safety.md +0 -9
- package/.agent-src/rules/scope-control.md +0 -9
- package/.agent-src/rules/security-sensitive-stop.md +0 -9
- package/.agent-src/rules/size-enforcement.md +0 -9
- package/.agent-src/rules/skill-improvement-trigger.md +0 -9
- package/.agent-src/rules/skill-quality.md +0 -9
- package/.agent-src/rules/slash-command-routing-policy.md +0 -9
- package/.agent-src/rules/strategy-safety-floor.md +0 -6
- package/.agent-src/rules/symfony-routing.md +0 -4
- package/.agent-src/rules/telegraph-speak.md +0 -9
- package/.agent-src/rules/think-before-action.md +0 -9
- package/.agent-src/rules/token-efficiency.md +0 -9
- package/.agent-src/rules/token-optimizer-maintenance.md +0 -9
- package/.agent-src/rules/tool-safety.md +0 -9
- package/.agent-src/rules/ui-audit-gate.md +0 -9
- package/.agent-src/rules/upstream-proposal.md +0 -9
- package/.agent-src/rules/user-interaction.md +0 -9
- package/.agent-src/rules/user-interrupt-priority.md +0 -9
- package/.agent-src/rules/verify-before-complete.md +0 -9
- package/.agent-src/skills/accessibility-auditor/SKILL.md +1 -9
- package/.agent-src/skills/activation-design/SKILL.md +1 -4
- package/.agent-src/skills/adr-create/SKILL.md +1 -9
- package/.agent-src/skills/adversarial-review/SKILL.md +1 -9
- package/.agent-src/skills/agent-docs-writing/SKILL.md +1 -9
- package/.agent-src/skills/agents-md-thin-root/SKILL.md +1 -9
- package/.agent-src/skills/ai-council/SKILL.md +1 -9
- package/.agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -9
- package/.agent-src/skills/analysis-skill-router/SKILL.md +1 -9
- package/.agent-src/skills/api-design/SKILL.md +1 -9
- package/.agent-src/skills/api-endpoint/SKILL.md +1 -9
- package/.agent-src/skills/api-testing/SKILL.md +1 -9
- package/.agent-src/skills/architecture-review-lens/SKILL.md +1 -9
- package/.agent-src/skills/artisan-commands/SKILL.md +1 -4
- package/.agent-src/skills/async-python-patterns/SKILL.md +1 -3
- package/.agent-src/skills/authz-review/SKILL.md +1 -9
- package/.agent-src/skills/aws-infrastructure/SKILL.md +1 -9
- package/.agent-src/skills/blade-ui/SKILL.md +1 -4
- package/.agent-src/skills/blast-radius-analyzer/SKILL.md +1 -9
- package/.agent-src/skills/bug-analyzer/SKILL.md +1 -9
- package/.agent-src/skills/build-buy-partner/SKILL.md +1 -7
- package/.agent-src/skills/canvas-design/SKILL.md +1 -3
- package/.agent-src/skills/character-consistency/SKILL.md +1 -3
- package/.agent-src/skills/check-refs/SKILL.md +1 -9
- package/.agent-src/skills/churn-prevention/SKILL.md +1 -5
- package/.agent-src/skills/code-refactoring/SKILL.md +1 -9
- package/.agent-src/skills/code-review/SKILL.md +1 -9
- package/.agent-src/skills/command-routing/SKILL.md +1 -9
- package/.agent-src/skills/command-writing/SKILL.md +1 -9
- package/.agent-src/skills/comp-banding/SKILL.md +1 -5
- package/.agent-src/skills/competitive-moat-analysis/SKILL.md +1 -7
- package/.agent-src/skills/competitive-positioning/SKILL.md +1 -5
- package/.agent-src/skills/composer-packages/SKILL.md +1 -4
- package/.agent-src/skills/condense-memory/SKILL.md +1 -9
- package/.agent-src/skills/content-funnel-design/SKILL.md +1 -5
- package/.agent-src/skills/context-authoring/SKILL.md +1 -9
- package/.agent-src/skills/context-document/SKILL.md +1 -9
- package/.agent-src/skills/contracts-cognition/SKILL.md +1 -5
- package/.agent-src/skills/conventional-commits-writing/SKILL.md +1 -9
- package/.agent-src/skills/copilot-agents-optimization/SKILL.md +1 -9
- package/.agent-src/skills/copilot-config/SKILL.md +1 -9
- package/.agent-src/skills/customer-research/SKILL.md +1 -4
- package/.agent-src/skills/dashboard-design/SKILL.md +1 -9
- package/.agent-src/skills/data-flow-mapper/SKILL.md +1 -9
- package/.agent-src/skills/data-handling-judgment/SKILL.md +1 -9
- package/.agent-src/skills/database/SKILL.md +1 -9
- package/.agent-src/skills/dcf-modeling/SKILL.md +1 -6
- package/.agent-src/skills/deal-qualification-meddic/SKILL.md +1 -5
- package/.agent-src/skills/decision-record/SKILL.md +1 -9
- package/.agent-src/skills/deep-reading-analyst/SKILL.md +2 -9
- package/.agent-src/skills/defense-in-depth/SKILL.md +1 -9
- package/.agent-src/skills/dependency-upgrade/SKILL.md +1 -9
- package/.agent-src/skills/description-assist/SKILL.md +1 -9
- package/.agent-src/skills/design-review/SKILL.md +1 -9
- package/.agent-src/skills/devcontainer/SKILL.md +1 -9
- package/.agent-src/skills/developer-like-execution/SKILL.md +1 -9
- package/.agent-src/skills/discovery-interview/SKILL.md +1 -4
- package/.agent-src/skills/doc-coauthoring/SKILL.md +1 -9
- package/.agent-src/skills/docker/SKILL.md +1 -9
- package/.agent-src/skills/editorial-calendar/SKILL.md +1 -5
- package/.agent-src/skills/eloquent/SKILL.md +1 -4
- package/.agent-src/skills/error-handling-patterns/SKILL.md +1 -9
- package/.agent-src/skills/estimate-ticket/SKILL.md +1 -5
- package/.agent-src/skills/existing-ui-audit/SKILL.md +1 -9
- package/.agent-src/skills/expansion-playbook/SKILL.md +1 -5
- package/.agent-src/skills/fe-design/SKILL.md +1 -9
- package/.agent-src/skills/feature-planning/SKILL.md +1 -5
- package/.agent-src/skills/file-editor/SKILL.md +1 -9
- package/.agent-src/skills/finishing-a-development-branch/SKILL.md +1 -9
- package/.agent-src/skills/flux/SKILL.md +1 -4
- package/.agent-src/skills/forecast-accuracy/SKILL.md +1 -5
- package/.agent-src/skills/forecasting/SKILL.md +1 -5
- package/.agent-src/skills/form-handler/SKILL.md +1 -9
- package/.agent-src/skills/fundraising-narrative/SKILL.md +1 -7
- package/.agent-src/skills/funnel-analysis/SKILL.md +1 -5
- package/.agent-src/skills/git-workflow/SKILL.md +1 -9
- package/.agent-src/skills/github-ci/SKILL.md +1 -9
- package/.agent-src/skills/grafana/SKILL.md +1 -9
- package/.agent-src/skills/gtm-launch/SKILL.md +1 -5
- package/.agent-src/skills/guideline-writing/SKILL.md +1 -9
- package/.agent-src/skills/hiring-loop-design/SKILL.md +1 -5
- package/.agent-src/skills/incident-commander/SKILL.md +1 -9
- package/.agent-src/skills/jira-integration/SKILL.md +1 -9
- package/.agent-src/skills/jobs-events/SKILL.md +1 -4
- package/.agent-src/skills/judge-bug-hunter/SKILL.md +1 -9
- package/.agent-src/skills/judge-code-quality/SKILL.md +1 -9
- package/.agent-src/skills/judge-security-auditor/SKILL.md +1 -9
- package/.agent-src/skills/judge-test-coverage/SKILL.md +1 -9
- package/.agent-src/skills/laravel/SKILL.md +1 -4
- package/.agent-src/skills/laravel-api-endpoint/SKILL.md +1 -4
- package/.agent-src/skills/laravel-dto/SKILL.md +1 -4
- package/.agent-src/skills/laravel-horizon/SKILL.md +1 -4
- package/.agent-src/skills/laravel-mail/SKILL.md +1 -4
- package/.agent-src/skills/laravel-middleware/SKILL.md +1 -4
- package/.agent-src/skills/laravel-migration/SKILL.md +1 -4
- package/.agent-src/skills/laravel-notifications/SKILL.md +1 -4
- package/.agent-src/skills/laravel-pennant/SKILL.md +1 -4
- package/.agent-src/skills/laravel-pulse/SKILL.md +1 -4
- package/.agent-src/skills/laravel-reverb/SKILL.md +1 -4
- package/.agent-src/skills/laravel-scheduling/SKILL.md +1 -4
- package/.agent-src/skills/laravel-validation/SKILL.md +1 -4
- package/.agent-src/skills/laravel-websocket/SKILL.md +1 -4
- package/.agent-src/skills/launch-readiness/SKILL.md +1 -7
- package/.agent-src/skills/learning-to-rule-or-skill/SKILL.md +1 -8
- package/.agent-src/skills/lint-skills/SKILL.md +1 -9
- package/.agent-src/skills/livewire/SKILL.md +1 -4
- package/.agent-src/skills/livewire-architect/SKILL.md +1 -4
- package/.agent-src/skills/logging-monitoring/SKILL.md +1 -9
- package/.agent-src/skills/market-entry-analysis/SKILL.md +1 -7
- package/.agent-src/skills/markitdown/SKILL.md +1 -9
- package/.agent-src/skills/mcp/SKILL.md +1 -9
- package/.agent-src/skills/mcp-builder/SKILL.md +1 -9
- package/.agent-src/skills/md-language-check/SKILL.md +1 -9
- package/.agent-src/skills/memory-consolidation/SKILL.md +1 -9
- package/.agent-src/skills/merge-conflicts/SKILL.md +1 -9
- package/.agent-src/skills/messaging-architecture/SKILL.md +1 -5
- package/.agent-src/skills/migration-architect/SKILL.md +1 -9
- package/.agent-src/skills/mobile-e2e-strategy/SKILL.md +1 -9
- package/.agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -9
- package/.agent-src/skills/module-management/SKILL.md +1 -9
- package/.agent-src/skills/motion-choreographer/SKILL.md +1 -3
- package/.agent-src/skills/multi-tenancy/SKILL.md +1 -9
- package/.agent-src/skills/nextjs-patterns/SKILL.md +1 -4
- package/.agent-src/skills/okr-tree-modeling/SKILL.md +1 -7
- package/.agent-src/skills/onboarding-design/SKILL.md +1 -5
- package/.agent-src/skills/onboarding-program/SKILL.md +1 -5
- package/.agent-src/skills/one-on-one-cadence/SKILL.md +1 -5
- package/.agent-src/skills/openapi/SKILL.md +1 -9
- package/.agent-src/skills/org-design/SKILL.md +1 -5
- package/.agent-src/skills/override-management/SKILL.md +1 -9
- package/.agent-src/skills/perf-feedback-craft/SKILL.md +1 -5
- package/.agent-src/skills/performance/SKILL.md +1 -9
- package/.agent-src/skills/performance-analysis/SKILL.md +1 -9
- package/.agent-src/skills/persona-writing/SKILL.md +1 -9
- package/.agent-src/skills/pest-testing/SKILL.md +1 -4
- package/.agent-src/skills/php-coder/SKILL.md +1 -4
- package/.agent-src/skills/php-debugging/SKILL.md +1 -4
- package/.agent-src/skills/php-service/SKILL.md +1 -4
- package/.agent-src/skills/pipeline-strategy/SKILL.md +1 -5
- package/.agent-src/skills/pixar-storyteller/SKILL.md +1 -3
- package/.agent-src/skills/playwright-architect/SKILL.md +1 -9
- package/.agent-src/skills/playwright-testing/SKILL.md +1 -9
- package/.agent-src/skills/po-discovery/SKILL.md +1 -5
- package/.agent-src/skills/positioning-strategy/SKILL.md +1 -5
- package/.agent-src/skills/privacy-review/SKILL.md +1 -9
- package/.agent-src/skills/project-analysis-core/SKILL.md +2 -9
- package/.agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +2 -9
- package/.agent-src/skills/project-analysis-laravel/SKILL.md +1 -4
- package/.agent-src/skills/project-analysis-nextjs/SKILL.md +1 -4
- package/.agent-src/skills/project-analysis-node-express/SKILL.md +1 -3
- package/.agent-src/skills/project-analysis-react/SKILL.md +1 -4
- package/.agent-src/skills/project-analysis-symfony/SKILL.md +1 -4
- package/.agent-src/skills/project-analysis-zend-laminas/SKILL.md +1 -4
- package/.agent-src/skills/project-analyzer/SKILL.md +2 -9
- package/.agent-src/skills/project-docs/SKILL.md +1 -9
- package/.agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -9
- package/.agent-src/skills/prompt-optimizer/SKILL.md +1 -9
- package/.agent-src/skills/quality-tools/SKILL.md +1 -9
- package/.agent-src/skills/react-native-setup/SKILL.md +1 -4
- package/.agent-src/skills/react-shadcn-ui/SKILL.md +1 -4
- package/.agent-src/skills/readme-reviewer/SKILL.md +1 -9
- package/.agent-src/skills/readme-writing/SKILL.md +1 -9
- package/.agent-src/skills/readme-writing-package/SKILL.md +1 -9
- package/.agent-src/skills/receiving-code-review/SKILL.md +1 -9
- package/.agent-src/skills/refine-prompt/SKILL.md +1 -9
- package/.agent-src/skills/refine-ticket/SKILL.md +1 -5
- package/.agent-src/skills/release-comms/SKILL.md +1 -5
- package/.agent-src/skills/repomix-packer/SKILL.md +2 -9
- package/.agent-src/skills/requesting-code-review/SKILL.md +1 -9
- package/.agent-src/skills/retention-loops/SKILL.md +1 -5
- package/.agent-src/skills/review-routing/SKILL.md +1 -9
- package/.agent-src/skills/rice-prioritization/SKILL.md +1 -5
- package/.agent-src/skills/risk-officer/SKILL.md +1 -9
- package/.agent-src/skills/roadmap-management/SKILL.md +1 -9
- package/.agent-src/skills/roadmap-writing/SKILL.md +1 -9
- package/.agent-src/skills/rtk-output-filtering/SKILL.md +1 -9
- package/.agent-src/skills/rule-refactor/SKILL.md +1 -9
- package/.agent-src/skills/rule-writing/SKILL.md +1 -9
- package/.agent-src/skills/runway-cognition/SKILL.md +1 -5
- package/.agent-src/skills/scenario-modeling/SKILL.md +1 -6
- package/.agent-src/skills/scene-expander/SKILL.md +1 -3
- package/.agent-src/skills/script-writing/SKILL.md +1 -9
- package/.agent-src/skills/secrets-management/SKILL.md +1 -9
- package/.agent-src/skills/security/SKILL.md +1 -9
- package/.agent-src/skills/security-audit/SKILL.md +1 -9
- package/.agent-src/skills/sentry-integration/SKILL.md +1 -9
- package/.agent-src/skills/sequential-thinking/SKILL.md +1 -9
- package/.agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -9
- package/.agent-src/skills/skill-management/SKILL.md +1 -8
- package/.agent-src/skills/skill-reviewer/SKILL.md +1 -9
- package/.agent-src/skills/skill-writing/SKILL.md +1 -8
- package/.agent-src/skills/sql-writing/SKILL.md +1 -9
- package/.agent-src/skills/stakeholder-tradeoff/SKILL.md +1 -5
- package/.agent-src/skills/subagent-orchestration/SKILL.md +1 -9
- package/.agent-src/skills/symfony-workflow/SKILL.md +1 -4
- package/.agent-src/skills/systematic-debugging/SKILL.md +1 -9
- package/.agent-src/skills/tailwind-engineer/SKILL.md +1 -9
- package/.agent-src/skills/tech-debt-tracker/SKILL.md +1 -9
- package/.agent-src/skills/technical-specification/SKILL.md +1 -5
- package/.agent-src/skills/terraform/SKILL.md +1 -9
- package/.agent-src/skills/terragrunt/SKILL.md +1 -9
- package/.agent-src/skills/test-driven-development/SKILL.md +1 -9
- package/.agent-src/skills/test-performance/SKILL.md +1 -9
- package/.agent-src/skills/testing-anti-patterns/SKILL.md +1 -9
- package/.agent-src/skills/threat-modeling/SKILL.md +1 -9
- package/.agent-src/skills/throughput-vs-morale-tradeoff/SKILL.md +1 -5
- package/.agent-src/skills/token-optimizer/SKILL.md +1 -9
- package/.agent-src/skills/traefik/SKILL.md +1 -9
- package/.agent-src/skills/ui-component-architect/SKILL.md +1 -9
- package/.agent-src/skills/unit-economics-modeling/SKILL.md +1 -5
- package/.agent-src/skills/universal-project-analysis/SKILL.md +2 -9
- package/.agent-src/skills/upstream-contribute/SKILL.md +1 -9
- package/.agent-src/skills/using-git-worktrees/SKILL.md +1 -9
- package/.agent-src/skills/validate-feature-fit/SKILL.md +1 -9
- package/.agent-src/skills/verify-completion-evidence/SKILL.md +1 -9
- package/.agent-src/skills/video-director/SKILL.md +1 -3
- package/.agent-src/skills/vision-articulation/SKILL.md +1 -7
- package/.agent-src/skills/voc-extract/SKILL.md +1 -4
- package/.agent-src/skills/voice-and-tone-design/SKILL.md +1 -5
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +27 -206
- package/README.md +5 -0
- package/config/agent-settings.template.yml +13 -0
- package/dist/cli/registry.js +2 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +358 -358
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +2 -2
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +3 -3
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +3 -3
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/server/schemas/settings.js +4 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/ui/assets/{index-Tk7lkVH8.js → index-DVsyUMZe.js} +2 -2
- package/dist/ui/assets/index-DVsyUMZe.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/archive/CHANGELOG-pre-5.4.0.md +260 -0
- package/docs/contracts/consumer-bridge.md +2 -0
- package/docs/contracts/multi-tool-projection-fidelity.md +19 -0
- package/docs/contracts/release-pr-gating.md +6 -1
- package/docs/decisions/ADR-020-global-only-consumer-scope.md +24 -0
- package/docs/decisions/ADR-034-per-skill-model-recommendation-transport.md +63 -0
- package/docs/decisions/ADR-035-model-capability-tiers.md +104 -0
- package/docs/decisions/INDEX.md +2 -0
- package/docs/getting-started.md +23 -0
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +25 -0
- package/package.json +1 -1
- package/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/scripts/_cli/cmd_doctor.py +44 -1
- package/scripts/_cli/cmd_refresh.py +173 -0
- package/scripts/_cli/cmd_upgrade.py +142 -0
- package/scripts/_dispatch.bash +20 -0
- package/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/scripts/backfill_model_tier.py +182 -0
- package/scripts/build_discovery_manifest.py +20 -3
- package/scripts/check_artefact_checksums.py +11 -4
- package/scripts/check_release_pr_shape.py +7 -0
- package/scripts/condense.py +148 -18
- package/scripts/hooks/dispatch_hook.py +39 -0
- package/scripts/install +14 -0
- package/scripts/lint_framework_leakage_allowlist.json +108 -78
- package/scripts/lint_frontmatter_boilerplate.py +77 -0
- package/scripts/lint_model_tier_coverage.py +73 -0
- package/scripts/migrate_frontmatter_defaults.py +245 -0
- package/scripts/roadmap_progress_hook.py +28 -2
- package/scripts/schemas/command.schema.json +17 -5
- package/scripts/schemas/persona.schema.json +4 -2
- package/scripts/schemas/rule.schema.json +8 -6
- package/scripts/schemas/skill.schema.json +18 -6
- package/scripts/skill_linter.py +21 -9
- package/scripts/smoke/skills.sh +4 -1
- package/scripts/validate_frontmatter.py +74 -0
- package/dist/ui/assets/index-Tk7lkVH8.js.map +0 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Migrate artefact frontmatter to omit fields equal to their schema default.
|
|
3
|
+
|
|
4
|
+
Phase 2 of `road-to-abstraction-reduction.md`. For every skill / rule /
|
|
5
|
+
command / persona, drop any frontmatter field whose value equals the
|
|
6
|
+
`default` declared in its `scripts/schemas/*.json` (preflight Decision C:
|
|
7
|
+
value-equals-default, type-safe). Fields without a schema default
|
|
8
|
+
(`skill.execution.type`, `command.type`, `rule.validator_ignore`) are never
|
|
9
|
+
touched.
|
|
10
|
+
|
|
11
|
+
The loader injects the same defaults at read time
|
|
12
|
+
(`validate_frontmatter.apply_schema_defaults`), so consumers see the field
|
|
13
|
+
present regardless. Idempotent: a second run is a no-op.
|
|
14
|
+
|
|
15
|
+
CLI:
|
|
16
|
+
python3 scripts/migrate_frontmatter_defaults.py [--dry-run] [--deltas PATH]
|
|
17
|
+
|
|
18
|
+
Exit codes: 0 always (reports counts); non-zero only on I/O error.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import sys
|
|
24
|
+
from collections import defaultdict
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
29
|
+
from validate_frontmatter import load_schema, parse_frontmatter # noqa: E402
|
|
30
|
+
from _lib.agent_src import artefact_roots # noqa: E402
|
|
31
|
+
|
|
32
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
33
|
+
DEFAULT_DELTAS = ROOT / "agents" / "evidence" / "analysis" / "abstraction-reduction-deltas.md"
|
|
34
|
+
|
|
35
|
+
# (subdir, glob, schema name)
|
|
36
|
+
_CATEGORIES = [
|
|
37
|
+
("skills", "SKILL.md", "skill"),
|
|
38
|
+
("rules", "*.md", "rule"),
|
|
39
|
+
("commands", "*.md", "command"),
|
|
40
|
+
("personas", "*.md", "persona"),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
_FM_RE_OPEN = "---\n"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _same(value: Any, default: Any) -> bool:
|
|
47
|
+
"""Type-safe equality. `True == 1` and `1.0 == 1` must NOT match across
|
|
48
|
+
types (preflight Decision C). bool is checked first because in Python
|
|
49
|
+
`isinstance(True, int)` is True."""
|
|
50
|
+
if isinstance(default, bool):
|
|
51
|
+
return isinstance(value, bool) and value == default
|
|
52
|
+
if isinstance(value, bool):
|
|
53
|
+
return False
|
|
54
|
+
return type(value) is type(default) and value == default
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _plan_drops(fm: dict[str, Any], schema: dict[str, Any]) -> tuple[set[str], set[str], dict[str, set[str]]]:
|
|
58
|
+
"""Return (top_level_drops, full_block_drops, partial_block_drops).
|
|
59
|
+
|
|
60
|
+
- top_level_drops: scalar keys whose value == default → drop the line.
|
|
61
|
+
- full_block_drops: object keys where every *present* sub-key is droppable
|
|
62
|
+
→ drop the whole block.
|
|
63
|
+
- partial_block_drops: object key → set of droppable sub-keys (block kept).
|
|
64
|
+
"""
|
|
65
|
+
top: set[str] = set()
|
|
66
|
+
full: set[str] = set()
|
|
67
|
+
partial: dict[str, set[str]] = {}
|
|
68
|
+
props = schema.get("properties", {})
|
|
69
|
+
for key, prop in props.items():
|
|
70
|
+
if not isinstance(prop, dict):
|
|
71
|
+
continue
|
|
72
|
+
if "default" in prop:
|
|
73
|
+
if key in fm and _same(fm[key], prop["default"]):
|
|
74
|
+
top.add(key)
|
|
75
|
+
elif prop.get("type") == "object" and isinstance(fm.get(key), dict):
|
|
76
|
+
sub_props = prop.get("properties", {})
|
|
77
|
+
droppable = {
|
|
78
|
+
sk for sk, sp in sub_props.items()
|
|
79
|
+
if isinstance(sp, dict) and "default" in sp
|
|
80
|
+
and sk in fm[key] and _same(fm[key][sk], sp["default"])
|
|
81
|
+
}
|
|
82
|
+
if not droppable:
|
|
83
|
+
continue
|
|
84
|
+
present = set(fm[key].keys())
|
|
85
|
+
if present <= droppable:
|
|
86
|
+
full.add(key)
|
|
87
|
+
else:
|
|
88
|
+
partial[key] = droppable
|
|
89
|
+
return top, full, partial
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _indent(line: str) -> int:
|
|
93
|
+
return len(line) - len(line.lstrip(" "))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _rewrite_fm_body(body: str, top: set[str], full: set[str], partial: dict[str, set[str]]) -> str:
|
|
97
|
+
"""Remove the planned lines from a frontmatter body, preserving everything
|
|
98
|
+
else byte-for-byte."""
|
|
99
|
+
lines = body.split("\n")
|
|
100
|
+
out: list[str] = []
|
|
101
|
+
skipping_block = False
|
|
102
|
+
current_block: str | None = None
|
|
103
|
+
for line in lines:
|
|
104
|
+
stripped = line.strip()
|
|
105
|
+
ind = _indent(line)
|
|
106
|
+
if skipping_block:
|
|
107
|
+
# Consume the block's indented children (and blank lines) until a
|
|
108
|
+
# top-level (indent-0, non-blank) line appears.
|
|
109
|
+
if stripped == "" or ind > 0:
|
|
110
|
+
continue
|
|
111
|
+
skipping_block = False
|
|
112
|
+
current_block = None
|
|
113
|
+
if ind == 0 and stripped and not stripped.startswith("#"):
|
|
114
|
+
key = stripped.split(":", 1)[0].strip()
|
|
115
|
+
if key in top:
|
|
116
|
+
continue
|
|
117
|
+
if key in full:
|
|
118
|
+
skipping_block = True
|
|
119
|
+
continue
|
|
120
|
+
current_block = key if key in partial else None
|
|
121
|
+
out.append(line)
|
|
122
|
+
continue
|
|
123
|
+
# Indented line belonging to current_block.
|
|
124
|
+
if current_block is not None and ind > 0 and ":" in stripped:
|
|
125
|
+
sub_key = stripped.split(":", 1)[0].strip()
|
|
126
|
+
if sub_key in partial.get(current_block, set()):
|
|
127
|
+
continue
|
|
128
|
+
out.append(line)
|
|
129
|
+
return "\n".join(out)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _migrate_file(path: Path, schema: dict[str, Any]) -> int:
|
|
133
|
+
text = path.read_text(encoding="utf-8")
|
|
134
|
+
fm, _ = parse_frontmatter(text)
|
|
135
|
+
if not isinstance(fm, dict):
|
|
136
|
+
return 0
|
|
137
|
+
top, full, partial = _plan_drops(fm, schema)
|
|
138
|
+
if not (top or full or partial):
|
|
139
|
+
return 0
|
|
140
|
+
# Locate the frontmatter body span (after the opening `---\n`).
|
|
141
|
+
if not text.startswith(_FM_RE_OPEN):
|
|
142
|
+
return 0
|
|
143
|
+
end = text.find("\n---\n", len(_FM_RE_OPEN))
|
|
144
|
+
if end == -1:
|
|
145
|
+
return 0
|
|
146
|
+
body = text[len(_FM_RE_OPEN):end]
|
|
147
|
+
new_body = _rewrite_fm_body(body, top, full, partial)
|
|
148
|
+
if new_body == body:
|
|
149
|
+
return 0
|
|
150
|
+
new_text = _FM_RE_OPEN + new_body + text[end:]
|
|
151
|
+
removed = body.count("\n") - new_body.count("\n")
|
|
152
|
+
path.write_text(new_text, encoding="utf-8")
|
|
153
|
+
return removed
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _iter(category_subdir: str, glob: str):
|
|
157
|
+
"""Mirror `validate_frontmatter._iter_artefacts` exactly: skills / rules /
|
|
158
|
+
commands recurse; personas are **non-recursive** (`glob`, not `rglob`) so
|
|
159
|
+
advisor personas (`personas/advisors/*.md`, a different schema) and the
|
|
160
|
+
`_template-specialist/` scaffold are never migrated."""
|
|
161
|
+
for root in artefact_roots():
|
|
162
|
+
base = root / category_subdir
|
|
163
|
+
if not base.exists():
|
|
164
|
+
continue
|
|
165
|
+
paths = base.glob(glob) if category_subdir == "personas" else base.rglob(glob)
|
|
166
|
+
for p in sorted(paths):
|
|
167
|
+
if p.is_file() and not p.is_symlink():
|
|
168
|
+
if category_subdir == "personas" and p.name.lower() == "readme.md":
|
|
169
|
+
continue
|
|
170
|
+
yield p
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def run(apply: bool, deltas_path: Path) -> int:
|
|
174
|
+
per_class_lines: dict[str, int] = defaultdict(int)
|
|
175
|
+
per_class_files: dict[str, int] = defaultdict(int)
|
|
176
|
+
for subdir, glob, schema_name in _CATEGORIES:
|
|
177
|
+
schema = load_schema(schema_name)
|
|
178
|
+
for path in _iter(subdir, glob):
|
|
179
|
+
if apply:
|
|
180
|
+
removed = _migrate_file(path, schema)
|
|
181
|
+
else:
|
|
182
|
+
# Dry-run: compute the delta without writing.
|
|
183
|
+
text = path.read_text(encoding="utf-8")
|
|
184
|
+
fm, _ = parse_frontmatter(text)
|
|
185
|
+
if not isinstance(fm, dict) or not text.startswith(_FM_RE_OPEN):
|
|
186
|
+
continue
|
|
187
|
+
end = text.find("\n---\n", len(_FM_RE_OPEN))
|
|
188
|
+
if end == -1:
|
|
189
|
+
continue
|
|
190
|
+
body = text[len(_FM_RE_OPEN):end]
|
|
191
|
+
top, full, partial = _plan_drops(fm, schema)
|
|
192
|
+
new_body = _rewrite_fm_body(body, top, full, partial)
|
|
193
|
+
removed = body.count("\n") - new_body.count("\n")
|
|
194
|
+
if removed:
|
|
195
|
+
per_class_lines[schema_name] += removed
|
|
196
|
+
per_class_files[schema_name] += 1
|
|
197
|
+
|
|
198
|
+
total_lines = sum(per_class_lines.values())
|
|
199
|
+
total_files = sum(per_class_files.values())
|
|
200
|
+
verb = "would remove" if not apply else "removed"
|
|
201
|
+
print(f"frontmatter-default migration ({'dry-run' if not apply else 'apply'}):")
|
|
202
|
+
for schema_name, _glob, _sn in [(c[2], c[1], c[2]) for c in _CATEGORIES]:
|
|
203
|
+
if per_class_files.get(schema_name):
|
|
204
|
+
print(f" {schema_name:8s}: {verb} {per_class_lines[schema_name]:5d} lines "
|
|
205
|
+
f"across {per_class_files[schema_name]} files")
|
|
206
|
+
print(f" {'TOTAL':8s}: {verb} {total_lines} lines across {total_files} files")
|
|
207
|
+
|
|
208
|
+
if not apply:
|
|
209
|
+
_write_deltas(deltas_path, per_class_lines, per_class_files, total_lines, total_files)
|
|
210
|
+
print(f" delta report → {deltas_path.relative_to(ROOT)}")
|
|
211
|
+
return 0
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _write_deltas(path: Path, lines: dict[str, int], files: dict[str, int],
|
|
215
|
+
total_lines: int, total_files: int) -> None:
|
|
216
|
+
rows = "\n".join(
|
|
217
|
+
f"| {sn} | {files.get(sn, 0)} | {lines.get(sn, 0)} |"
|
|
218
|
+
for _sd, _g, sn in _CATEGORIES if files.get(sn)
|
|
219
|
+
)
|
|
220
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
221
|
+
path.write_text(
|
|
222
|
+
"# Abstraction-reduction — frontmatter line-count delta\n\n"
|
|
223
|
+
"> Dry-run prediction from `scripts/migrate_frontmatter_defaults.py "
|
|
224
|
+
"--dry-run` (road-to-abstraction-reduction.md Phase 2 § Step 2). Lines\n"
|
|
225
|
+
"> are frontmatter lines dropped because their value equalled the\n"
|
|
226
|
+
"> schema default; the loader re-injects them at read time.\n\n"
|
|
227
|
+
"| Class | Files touched | Lines removed |\n"
|
|
228
|
+
"|---|---:|---:|\n"
|
|
229
|
+
f"{rows}\n"
|
|
230
|
+
f"| **TOTAL** | **{total_files}** | **{total_lines}** |\n",
|
|
231
|
+
encoding="utf-8",
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def main(argv: list[str] | None = None) -> int:
|
|
236
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
237
|
+
parser.add_argument("--dry-run", action="store_true", help="report the delta; write nothing.")
|
|
238
|
+
parser.add_argument("--deltas", type=Path, default=DEFAULT_DELTAS,
|
|
239
|
+
help="dry-run delta report output path.")
|
|
240
|
+
args = parser.parse_args(argv)
|
|
241
|
+
return run(apply=not args.dry_run, deltas_path=args.deltas)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if __name__ == "__main__":
|
|
245
|
+
sys.exit(main())
|
|
@@ -75,6 +75,26 @@ def _candidate_paths(payload: dict) -> list[str]:
|
|
|
75
75
|
return out
|
|
76
76
|
|
|
77
77
|
|
|
78
|
+
def _relativize(path: str, root: Path) -> str:
|
|
79
|
+
"""Make an absolute path project-relative so the `agents/roadmaps/` prefix
|
|
80
|
+
check fires.
|
|
81
|
+
|
|
82
|
+
Claude Code passes an absolute `tool_input.file_path`
|
|
83
|
+
(`/Users/.../<repo>/agents/roadmaps/x.md`); Augment passes a repo-relative
|
|
84
|
+
one. Without this, an absolute path never matches the relative prefix and
|
|
85
|
+
the hook silently no-ops. Already-relative paths and out-of-tree paths are
|
|
86
|
+
returned unchanged — an out-of-tree roadmap correctly fails the prefix
|
|
87
|
+
check downstream.
|
|
88
|
+
"""
|
|
89
|
+
p = Path(path)
|
|
90
|
+
if not p.is_absolute():
|
|
91
|
+
return path
|
|
92
|
+
try:
|
|
93
|
+
return str(p.resolve().relative_to(root.resolve()))
|
|
94
|
+
except (ValueError, OSError):
|
|
95
|
+
return path
|
|
96
|
+
|
|
97
|
+
|
|
78
98
|
def _is_roadmap_touch(path: str) -> bool:
|
|
79
99
|
"""Return True if `path` is a roadmap file we should react to."""
|
|
80
100
|
norm = path.lstrip("./").replace("\\", "/")
|
|
@@ -126,7 +146,7 @@ def run(stdin_text: str, *, consumer_root: Path, verbose: bool = False) -> int:
|
|
|
126
146
|
if not isinstance(tool, str) or tool not in WRITE_TOOLS:
|
|
127
147
|
return 0
|
|
128
148
|
|
|
129
|
-
paths = _candidate_paths(payload)
|
|
149
|
+
paths = [_relativize(p, consumer_root) for p in _candidate_paths(payload)]
|
|
130
150
|
if not any(_is_roadmap_touch(p) for p in paths):
|
|
131
151
|
return 0
|
|
132
152
|
|
|
@@ -188,10 +208,16 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
188
208
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
189
209
|
parser.add_argument("--platform", default="generic",
|
|
190
210
|
help="informational platform tag (augment/claude/...)")
|
|
211
|
+
parser.add_argument("--project-dir", default="",
|
|
212
|
+
help="project root override; falls back to cwd. The "
|
|
213
|
+
"Claude plugin passes $CLAUDE_PROJECT_DIR so a "
|
|
214
|
+
"globally-resolved binary (ADR-020) scans the "
|
|
215
|
+
"right project's agents/roadmaps/.")
|
|
191
216
|
parser.add_argument("--verbose", action="store_true",
|
|
192
217
|
help="emit one stderr line per invocation")
|
|
193
218
|
args = parser.parse_args(argv)
|
|
194
|
-
|
|
219
|
+
root = Path(args.project_dir).expanduser() if args.project_dir else Path.cwd()
|
|
220
|
+
return run(sys.stdin.read(), consumer_root=root, verbose=args.verbose)
|
|
195
221
|
|
|
196
222
|
|
|
197
223
|
if __name__ == "__main__": # pragma: no cover
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"disable-model-invocation": {
|
|
26
26
|
"type": "boolean",
|
|
27
27
|
"enum": [true],
|
|
28
|
+
"default": true,
|
|
28
29
|
"description": "Commands are always user-invoked; model-invocation is disabled."
|
|
29
30
|
},
|
|
30
31
|
"skills": {
|
|
@@ -77,6 +78,16 @@
|
|
|
77
78
|
"enum": ["deep"],
|
|
78
79
|
"description": "Optional reasoning-depth marker for AI Council invocations triggered by this command. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for architecture, refactoring, or bug-diagnosis commands. See .agent-src.uncondensed/skills/ai-council/SKILL.md."
|
|
79
80
|
},
|
|
81
|
+
"model_tier": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"enum": ["lite", "medium", "high", "inherit"],
|
|
84
|
+
"description": "Vendor-neutral capability band the command needs (ADR-035). Commands project as Claude skills, so high/medium/lite produce a native Claude `model:` (high→opus, medium→sonnet, lite→haiku) when model.auto_switch=auto; the generator owns that mapping. inherit keeps the session model. Non-Claude agents are suggestion-only. No vendor model names here."
|
|
85
|
+
},
|
|
86
|
+
"context": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"enum": ["large"],
|
|
89
|
+
"description": "Optional orthogonal modifier (ADR-035): the command needs a large-context model regardless of reasoning tier. Sparse — most omit it. Metadata only; does not change the native Claude `model:`."
|
|
90
|
+
},
|
|
80
91
|
"suggestion": {
|
|
81
92
|
"type": "object",
|
|
82
93
|
"additionalProperties": false,
|
|
@@ -135,6 +146,7 @@
|
|
|
135
146
|
"lifecycle": {
|
|
136
147
|
"type": "string",
|
|
137
148
|
"enum": ["active", "deprecated", "experimental", "archived"],
|
|
149
|
+
"default": "active",
|
|
138
150
|
"description": "ADR-013 lifecycle state."
|
|
139
151
|
},
|
|
140
152
|
"trust": {
|
|
@@ -142,9 +154,9 @@
|
|
|
142
154
|
"additionalProperties": false,
|
|
143
155
|
"required": ["level", "confidence", "human_review_required"],
|
|
144
156
|
"properties": {
|
|
145
|
-
"level": {"type": "string", "enum": ["core", "professional", "experimental", "advisory", "restricted"]},
|
|
146
|
-
"confidence": {"type": "string", "enum": ["high", "medium", "low"]},
|
|
147
|
-
"human_review_required": {"type": "boolean"}
|
|
157
|
+
"level": {"type": "string", "enum": ["core", "professional", "experimental", "advisory", "restricted"], "default": "core"},
|
|
158
|
+
"confidence": {"type": "string", "enum": ["high", "medium", "low"], "default": "high"},
|
|
159
|
+
"human_review_required": {"type": "boolean", "default": false}
|
|
148
160
|
},
|
|
149
161
|
"description": "ADR-013 trust block. Vocabulary mirrored by scripts/lint_artefact_frontmatter.py."
|
|
150
162
|
},
|
|
@@ -153,8 +165,8 @@
|
|
|
153
165
|
"additionalProperties": false,
|
|
154
166
|
"required": ["default", "removable"],
|
|
155
167
|
"properties": {
|
|
156
|
-
"default": {"type": "boolean"},
|
|
157
|
-
"removable": {"type": "boolean"}
|
|
168
|
+
"default": {"type": "boolean", "default": true},
|
|
169
|
+
"removable": {"type": "boolean", "default": false}
|
|
158
170
|
},
|
|
159
171
|
"description": "ADR-013 install hints (default-on at consumer install; user-removable)."
|
|
160
172
|
},
|
|
@@ -37,11 +37,13 @@
|
|
|
37
37
|
},
|
|
38
38
|
"version": {
|
|
39
39
|
"type": "string",
|
|
40
|
-
"pattern": "^[0-9]+(\\.[0-9]+){0,2}$"
|
|
40
|
+
"pattern": "^[0-9]+(\\.[0-9]+){0,2}$",
|
|
41
|
+
"default": "1.0"
|
|
41
42
|
},
|
|
42
43
|
"source": {
|
|
43
44
|
"type": "string",
|
|
44
|
-
"enum": ["package", "project"]
|
|
45
|
+
"enum": ["package", "project"],
|
|
46
|
+
"default": "package"
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
}
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"source": {
|
|
16
16
|
"type": "string",
|
|
17
|
-
"enum": ["package", "project"]
|
|
17
|
+
"enum": ["package", "project"],
|
|
18
|
+
"default": "package"
|
|
18
19
|
},
|
|
19
20
|
"description": {
|
|
20
21
|
"type": "string",
|
|
@@ -116,6 +117,7 @@
|
|
|
116
117
|
"lifecycle": {
|
|
117
118
|
"type": "string",
|
|
118
119
|
"enum": ["active", "deprecated", "experimental", "archived"],
|
|
120
|
+
"default": "active",
|
|
119
121
|
"description": "ADR-013 lifecycle state."
|
|
120
122
|
},
|
|
121
123
|
"trust": {
|
|
@@ -123,9 +125,9 @@
|
|
|
123
125
|
"additionalProperties": false,
|
|
124
126
|
"required": ["level", "confidence", "human_review_required"],
|
|
125
127
|
"properties": {
|
|
126
|
-
"level": {"type": "string", "enum": ["core", "professional", "experimental", "advisory", "restricted"]},
|
|
127
|
-
"confidence": {"type": "string", "enum": ["high", "medium", "low"]},
|
|
128
|
-
"human_review_required": {"type": "boolean"}
|
|
128
|
+
"level": {"type": "string", "enum": ["core", "professional", "experimental", "advisory", "restricted"], "default": "core"},
|
|
129
|
+
"confidence": {"type": "string", "enum": ["high", "medium", "low"], "default": "high"},
|
|
130
|
+
"human_review_required": {"type": "boolean", "default": false}
|
|
129
131
|
},
|
|
130
132
|
"description": "ADR-013 trust block. Vocabulary mirrored by scripts/lint_artefact_frontmatter.py."
|
|
131
133
|
},
|
|
@@ -134,8 +136,8 @@
|
|
|
134
136
|
"additionalProperties": false,
|
|
135
137
|
"required": ["default", "removable"],
|
|
136
138
|
"properties": {
|
|
137
|
-
"default": {"type": "boolean"},
|
|
138
|
-
"removable": {"type": "boolean"}
|
|
139
|
+
"default": {"type": "boolean", "default": true},
|
|
140
|
+
"removable": {"type": "boolean", "default": false}
|
|
139
141
|
},
|
|
140
142
|
"description": "ADR-013 install hints (default-on at consumer install; user-removable)."
|
|
141
143
|
}
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
},
|
|
21
21
|
"source": {
|
|
22
22
|
"type": "string",
|
|
23
|
-
"enum": ["package", "project"]
|
|
23
|
+
"enum": ["package", "project"],
|
|
24
|
+
"default": "package"
|
|
24
25
|
},
|
|
25
26
|
"domain": {
|
|
26
27
|
"type": "string",
|
|
@@ -71,6 +72,16 @@
|
|
|
71
72
|
"minLength": 1,
|
|
72
73
|
"description": "Conditions under which the skill should be archived and replaced with a 50-line pointer (e.g. all referenced modules adopted as project-local guidelines, dispatch logic moved to a project-native router). Required when `external_source` is set."
|
|
73
74
|
},
|
|
75
|
+
"model_tier": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"enum": ["lite", "medium", "high", "inherit"],
|
|
78
|
+
"description": "Vendor-neutral capability band the skill needs (ADR-035). high/medium/lite project to a native Claude `model:` (high→opus, medium→sonnet, lite→haiku) when model.auto_switch=auto; the generator owns that mapping exclusively. inherit keeps the session model. Non-Claude agents are suggestion-only — the model-recommendation rule names the tier and the agent resolves its own model. No vendor model names here."
|
|
79
|
+
},
|
|
80
|
+
"context": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"enum": ["large"],
|
|
83
|
+
"description": "Optional orthogonal modifier (ADR-035): the skill needs a large-context model regardless of reasoning tier (e.g. summarising a 500-page log). Sparse — most skills omit it. Metadata only; does not change the native Claude `model:` (the tier owns the model choice)."
|
|
84
|
+
},
|
|
74
85
|
"council_depth": {
|
|
75
86
|
"type": "string",
|
|
76
87
|
"enum": ["deep"],
|
|
@@ -140,6 +151,7 @@
|
|
|
140
151
|
"lifecycle": {
|
|
141
152
|
"type": "string",
|
|
142
153
|
"enum": ["active", "deprecated", "experimental", "archived"],
|
|
154
|
+
"default": "active",
|
|
143
155
|
"description": "ADR-013 lifecycle state."
|
|
144
156
|
},
|
|
145
157
|
"trust": {
|
|
@@ -147,9 +159,9 @@
|
|
|
147
159
|
"additionalProperties": false,
|
|
148
160
|
"required": ["level", "confidence", "human_review_required"],
|
|
149
161
|
"properties": {
|
|
150
|
-
"level": {"type": "string", "enum": ["core", "professional", "experimental", "advisory", "restricted"]},
|
|
151
|
-
"confidence": {"type": "string", "enum": ["high", "medium", "low"]},
|
|
152
|
-
"human_review_required": {"type": "boolean"}
|
|
162
|
+
"level": {"type": "string", "enum": ["core", "professional", "experimental", "advisory", "restricted"], "default": "core"},
|
|
163
|
+
"confidence": {"type": "string", "enum": ["high", "medium", "low"], "default": "high"},
|
|
164
|
+
"human_review_required": {"type": "boolean", "default": false}
|
|
153
165
|
},
|
|
154
166
|
"description": "ADR-013 trust block. Vocabulary mirrored by scripts/lint_artefact_frontmatter.py."
|
|
155
167
|
},
|
|
@@ -158,8 +170,8 @@
|
|
|
158
170
|
"additionalProperties": false,
|
|
159
171
|
"required": ["default", "removable"],
|
|
160
172
|
"properties": {
|
|
161
|
-
"default": {"type": "boolean"},
|
|
162
|
-
"removable": {"type": "boolean"}
|
|
173
|
+
"default": {"type": "boolean", "default": true},
|
|
174
|
+
"removable": {"type": "boolean", "default": false}
|
|
163
175
|
},
|
|
164
176
|
"description": "ADR-013 install hints (default-on at consumer install; user-removable)."
|
|
165
177
|
}
|
package/scripts/skill_linter.py
CHANGED
|
@@ -33,6 +33,7 @@ from typing import Iterable, List, Literal, Optional
|
|
|
33
33
|
# Sibling module — stdlib-only frontmatter schema validator.
|
|
34
34
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
35
35
|
from validate_frontmatter import ( # noqa: E402
|
|
36
|
+
apply_schema_defaults,
|
|
36
37
|
parse_frontmatter as parse_frontmatter_for_schema,
|
|
37
38
|
load_schema,
|
|
38
39
|
validate as validate_against_schema,
|
|
@@ -1511,11 +1512,10 @@ def lint_rule(path: Path, text: str) -> LintResult:
|
|
|
1511
1512
|
elif rule_type not in VALID_RULE_TYPES:
|
|
1512
1513
|
issues.append(Issue("error", "invalid_type", f"Invalid type '{rule_type}'; must be 'always', 'auto', or 'manual'"))
|
|
1513
1514
|
|
|
1514
|
-
# source field
|
|
1515
|
+
# source field — optional (schema default `package` injected at read);
|
|
1516
|
+
# validate the value only when present.
|
|
1515
1517
|
rule_source = extract_frontmatter_field(frontmatter, SOURCE_PATTERN)
|
|
1516
|
-
if rule_source is None:
|
|
1517
|
-
issues.append(Issue("error", "missing_source", "Frontmatter missing 'source' field (must be 'package' or 'project')"))
|
|
1518
|
-
elif rule_source not in VALID_RULE_SOURCES:
|
|
1518
|
+
if rule_source is not None and rule_source not in VALID_RULE_SOURCES:
|
|
1519
1519
|
issues.append(Issue("error", "invalid_source", f"Invalid source '{rule_source}'; must be 'package' or 'project'"))
|
|
1520
1520
|
|
|
1521
1521
|
# description required for auto rules
|
|
@@ -1689,12 +1689,10 @@ def lint_command(path: Path, text: str) -> LintResult:
|
|
|
1689
1689
|
if not name_match or not name_match.group(1).strip():
|
|
1690
1690
|
issues.append(Issue("error", "missing_name", "Frontmatter missing 'name' field"))
|
|
1691
1691
|
|
|
1692
|
-
# disable-model-invocation field
|
|
1692
|
+
# disable-model-invocation field — optional (schema default `true`
|
|
1693
|
+
# injected at read); validate the value only when present.
|
|
1693
1694
|
dmi_match = DISABLE_MODEL_PATTERN.search(frontmatter)
|
|
1694
|
-
if
|
|
1695
|
-
issues.append(Issue("error", "missing_disable_model_invocation",
|
|
1696
|
-
"Frontmatter missing 'disable-model-invocation: true' (required for Claude Code)"))
|
|
1697
|
-
elif dmi_match.group(1) != "true":
|
|
1695
|
+
if dmi_match and dmi_match.group(1) != "true":
|
|
1698
1696
|
issues.append(Issue("warning", "disable_model_invocation_false",
|
|
1699
1697
|
"disable-model-invocation should be 'true' for commands"))
|
|
1700
1698
|
|
|
@@ -1839,6 +1837,11 @@ def lint_persona(path: Path, text: str) -> LintResult:
|
|
|
1839
1837
|
"role": re.compile(r'^role:\s*"?(.+?)"?\s*$', re.MULTILINE),
|
|
1840
1838
|
"description": re.compile(r'^description:\s*"?(.+?)"?\s*$', re.MULTILINE),
|
|
1841
1839
|
"tier": re.compile(r'^tier:\s*"?(\w+)"?\s*$', re.MULTILINE),
|
|
1840
|
+
}
|
|
1841
|
+
# `version` (default "1.0") and `source` (default "package") carry schema
|
|
1842
|
+
# defaults — they are injected at read time, so omitting them is valid.
|
|
1843
|
+
# Validate the value only when present; never require presence.
|
|
1844
|
+
optional_defaulted = {
|
|
1842
1845
|
"version": re.compile(r'^version:\s*"?(.+?)"?\s*$', re.MULTILINE),
|
|
1843
1846
|
"source": re.compile(r'^source:\s*"?(package|project)"?\s*$', re.MULTILINE),
|
|
1844
1847
|
}
|
|
@@ -1849,6 +1852,10 @@ def lint_persona(path: Path, text: str) -> LintResult:
|
|
|
1849
1852
|
issues.append(Issue("error", f"missing_{field}", f"Persona frontmatter must declare `{field}`"))
|
|
1850
1853
|
else:
|
|
1851
1854
|
parsed[field] = value
|
|
1855
|
+
for field, pattern in optional_defaulted.items():
|
|
1856
|
+
value = extract_frontmatter_field(frontmatter, pattern)
|
|
1857
|
+
if value:
|
|
1858
|
+
parsed[field] = value
|
|
1852
1859
|
|
|
1853
1860
|
# id matches filename stem
|
|
1854
1861
|
if "id" in parsed and parsed["id"] != path.stem:
|
|
@@ -3091,6 +3098,11 @@ def lint_frontmatter_schema(path: Path, text: str, artifact_type: str) -> List[I
|
|
|
3091
3098
|
# rules/commands/personas; avoid double-reporting here.
|
|
3092
3099
|
return []
|
|
3093
3100
|
|
|
3101
|
+
# Inject schema defaults before validating so artefacts that omit a field
|
|
3102
|
+
# equal to its default (post abstraction-reduction migration) still satisfy
|
|
3103
|
+
# `required` — mirrors validate_frontmatter's own loader path.
|
|
3104
|
+
apply_schema_defaults(data, schema)
|
|
3105
|
+
|
|
3094
3106
|
issues: List[Issue] = []
|
|
3095
3107
|
for error in validate_against_schema(data, schema):
|
|
3096
3108
|
code = f"schema_{error.rule}"
|
package/scripts/smoke/skills.sh
CHANGED
|
@@ -25,7 +25,7 @@ log() { [ "$quiet" = "1" ] || printf '%s\n' "$*"; }
|
|
|
25
25
|
result=$(python3 <<'PY'
|
|
26
26
|
import os, sys, time, hashlib, pathlib, glob
|
|
27
27
|
sys.path.insert(0, "scripts")
|
|
28
|
-
from validate_frontmatter import parse_frontmatter, load_schema, validate
|
|
28
|
+
from validate_frontmatter import parse_frontmatter, load_schema, validate, apply_schema_defaults
|
|
29
29
|
from _lib.agent_src import artefact_roots
|
|
30
30
|
|
|
31
31
|
# ADR-017: walk every source root, collect skill dirs by logical name.
|
|
@@ -60,6 +60,9 @@ for name in sample:
|
|
|
60
60
|
if fm is None:
|
|
61
61
|
failures.append(f"{name}: no frontmatter")
|
|
62
62
|
continue
|
|
63
|
+
# Inject schema defaults before validating: artefacts may omit a field
|
|
64
|
+
# equal to its default (abstraction-reduction), injected at read time.
|
|
65
|
+
apply_schema_defaults(fm, schema)
|
|
63
66
|
errs = validate(fm, schema)
|
|
64
67
|
if errs:
|
|
65
68
|
for e in errs:
|
|
@@ -33,6 +33,7 @@ __all__ = [
|
|
|
33
33
|
"validate",
|
|
34
34
|
"load_schema",
|
|
35
35
|
"parse_frontmatter",
|
|
36
|
+
"apply_schema_defaults",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
_FRONTMATTER_RE = re.compile(r"^---\n(.*?)\n---\n", re.DOTALL)
|
|
@@ -234,6 +235,75 @@ def load_schema(artefact_type: str) -> dict[str, Any]:
|
|
|
234
235
|
return data
|
|
235
236
|
|
|
236
237
|
|
|
238
|
+
# --- Schema-default injection ----------------------------------------------
|
|
239
|
+
|
|
240
|
+
def _object_defaults(schema: dict[str, Any]) -> dict[str, Any]:
|
|
241
|
+
"""Build the default value for an absent object property from the
|
|
242
|
+
``default`` keywords declared on its sub-properties. Returns ``{}`` when
|
|
243
|
+
no sub-property declares a default (so the object is never fabricated).
|
|
244
|
+
"""
|
|
245
|
+
out: dict[str, Any] = {}
|
|
246
|
+
for sub_key, sub_schema in (schema.get("properties") or {}).items():
|
|
247
|
+
if not isinstance(sub_schema, dict):
|
|
248
|
+
continue
|
|
249
|
+
if "default" in sub_schema:
|
|
250
|
+
out[sub_key] = sub_schema["default"]
|
|
251
|
+
elif sub_schema.get("type") == "object":
|
|
252
|
+
nested = _object_defaults(sub_schema)
|
|
253
|
+
if nested:
|
|
254
|
+
out[sub_key] = nested
|
|
255
|
+
return out
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def apply_schema_defaults(data: dict[str, Any], schema: dict[str, Any]) -> dict[str, Any]:
|
|
259
|
+
"""Inject schema ``default`` values into ``data`` for absent keys, in place.
|
|
260
|
+
|
|
261
|
+
Mirrors the contract in
|
|
262
|
+
``agents/evidence/analysis/abstraction-reduction-preflight.md``: a field
|
|
263
|
+
omitted on disk reads back as its schema default, so downstream consumers
|
|
264
|
+
that require the field present keep working unchanged after the
|
|
265
|
+
frontmatter-default migration (road-to-abstraction-reduction.md).
|
|
266
|
+
|
|
267
|
+
Behaviour:
|
|
268
|
+
- A scalar property with a ``default`` is injected when absent.
|
|
269
|
+
- An object property whose sub-properties declare defaults is, when absent,
|
|
270
|
+
reconstructed from those sub-defaults; when present (a dict), its absent
|
|
271
|
+
sub-keys are filled. Objects with no sub-defaults (e.g. ``execution``) are
|
|
272
|
+
never fabricated.
|
|
273
|
+
- Present values are never overwritten — injection only fills gaps.
|
|
274
|
+
|
|
275
|
+
Returns the same ``data`` dict for convenience. Non-dict input is returned
|
|
276
|
+
untouched.
|
|
277
|
+
"""
|
|
278
|
+
if not isinstance(data, dict):
|
|
279
|
+
return data
|
|
280
|
+
for key, prop in (schema.get("properties") or {}).items():
|
|
281
|
+
if not isinstance(prop, dict):
|
|
282
|
+
continue
|
|
283
|
+
if "default" in prop:
|
|
284
|
+
data.setdefault(key, prop["default"])
|
|
285
|
+
continue
|
|
286
|
+
if prop.get("type") == "object":
|
|
287
|
+
if key in data and isinstance(data[key], dict):
|
|
288
|
+
_fill_object_defaults(data[key], prop)
|
|
289
|
+
elif key not in data:
|
|
290
|
+
reconstructed = _object_defaults(prop)
|
|
291
|
+
if reconstructed:
|
|
292
|
+
data[key] = reconstructed
|
|
293
|
+
return data
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _fill_object_defaults(obj: dict[str, Any], schema: dict[str, Any]) -> None:
|
|
297
|
+
"""Fill absent sub-keys of a present object from sub-property defaults."""
|
|
298
|
+
for sub_key, sub_schema in (schema.get("properties") or {}).items():
|
|
299
|
+
if not isinstance(sub_schema, dict):
|
|
300
|
+
continue
|
|
301
|
+
if "default" in sub_schema:
|
|
302
|
+
obj.setdefault(sub_key, sub_schema["default"])
|
|
303
|
+
elif sub_schema.get("type") == "object" and isinstance(obj.get(sub_key), dict):
|
|
304
|
+
_fill_object_defaults(obj[sub_key], sub_schema)
|
|
305
|
+
|
|
306
|
+
|
|
237
307
|
# --- Validator core (Draft-07 subset) --------------------------------------
|
|
238
308
|
|
|
239
309
|
_JSON_TYPES: dict[str, tuple[type, ...]] = {
|
|
@@ -476,6 +546,10 @@ def _main() -> int:
|
|
|
476
546
|
# Other tooling flags missing frontmatter; don't double-report.
|
|
477
547
|
continue
|
|
478
548
|
schema = load_schema(artefact_type)
|
|
549
|
+
# Inject schema defaults before validation so artefacts that omit a
|
|
550
|
+
# field equal to its default still satisfy `required`
|
|
551
|
+
# (road-to-abstraction-reduction.md Phase 1).
|
|
552
|
+
apply_schema_defaults(data, schema)
|
|
479
553
|
errors = validate(data, schema)
|
|
480
554
|
fatal = [e for e in errors if e.severity == "error"]
|
|
481
555
|
warnings = [e for e in errors if e.severity == "warning"]
|