@event4u/agent-config 7.4.0 → 8.0.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/.claude-plugin/marketplace.json +11 -1
- package/AGENTS.md +9 -9
- package/CHANGELOG.md +373 -0
- package/README.md +35 -5
- package/dist/agent-src/commands/analytics/prune.md +1 -1
- package/dist/agent-src/commands/analytics/show.md +1 -1
- package/dist/agent-src/commands/analyze/decision.md +2 -2
- package/dist/agent-src/commands/analyze/incident.md +2 -2
- package/dist/agent-src/commands/analyze/near-miss.md +2 -2
- package/dist/agent-src/commands/analyze/postmortem.md +2 -2
- package/dist/agent-src/commands/analyze/premortem.md +2 -2
- package/dist/agent-src/commands/cost-report.md +25 -0
- package/dist/agent-src/commands/evals/analyze.json +30 -0
- package/dist/agent-src/commands/evals/mission-upgrade.json +30 -0
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/knowledge/forget.md +1 -1
- package/dist/agent-src/commands/knowledge/ingest.md +1 -1
- package/dist/agent-src/commands/knowledge/list.md +1 -1
- package/dist/agent-src/commands/memory/load.md +12 -11
- package/dist/agent-src/commands/memory/promote.md +30 -0
- package/dist/agent-src/commands/memory/propose.md +16 -2
- package/dist/agent-src/commands/mission/upgrade.md +1 -1
- package/dist/agent-src/commands/module/explore.md +11 -7
- package/dist/agent-src/commands/optimize-project.md +243 -0
- package/dist/agent-src/commands/optimize.md +5 -0
- package/dist/agent-src/commands/pr/create.md +37 -8
- package/dist/agent-src/commands/prediction-pool.md +2 -2
- package/dist/agent-src/commands/profile/activate.md +3 -3
- package/dist/agent-src/commands/profile/deactivate.md +2 -2
- package/dist/agent-src/commands/profile/show.md +3 -3
- package/dist/agent-src/commands/research/deep.md +5 -0
- package/dist/agent-src/commands/research/report.md +2 -1
- package/dist/agent-src/commands/review-changes.md +14 -7
- package/dist/agent-src/commands/roadmap/create.md +88 -10
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +15 -2
- package/dist/agent-src/commands/roadmap/process-phase.md +18 -6
- package/dist/agent-src/commands/roadmap/process-step.md +4 -0
- package/dist/agent-src/commands/roadmap.md +1 -1
- package/dist/agent-src/commands/security-audit-config.md +1 -1
- package/dist/agent-src/commands/sync-agent-settings.md +1 -1
- package/dist/agent-src/commands/sync-gitignore/fix.md +42 -6
- package/dist/agent-src/commands/team-knowledge/bootstrap.md +106 -0
- package/dist/agent-src/commands/team-knowledge/consolidate.md +105 -0
- package/dist/agent-src/commands/team-knowledge.md +64 -0
- package/dist/agent-src/contexts/authority/commit-mechanics.md +8 -0
- package/dist/agent-src/contexts/authority/destructive-mechanics.md +11 -0
- package/dist/agent-src/contexts/authority/scope-mechanics.md +25 -0
- package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +43 -0
- package/dist/agent-src/contexts/contracts/agents-md-anatomy.md +1 -1
- package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +2 -2
- package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +14 -4
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +11 -0
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +32 -8
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +107 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +71 -15
- package/dist/agent-src/contexts/execution/subagent-steering.md +41 -1
- package/dist/agent-src/contexts/override-system.md +1 -1
- package/dist/agent-src/personas/brand-strategist.md +0 -1
- package/dist/agent-src/personas/data-integrity.md +66 -0
- package/dist/agent-src/personas/design-director.md +0 -1
- package/dist/agent-src/personas/performance-engineer.md +66 -0
- package/dist/agent-src/personas/production-validator.md +73 -0
- package/dist/agent-src/rules/agent-authority.md +3 -4
- package/dist/agent-src/rules/analysis-skill-routing.md +3 -5
- package/dist/agent-src/rules/architecture.md +2 -4
- package/dist/agent-src/rules/artifact-drafting-protocol.md +35 -6
- package/dist/agent-src/rules/artifact-engagement-recording.md +11 -4
- package/dist/agent-src/rules/ask-when-uncertain.md +10 -14
- package/dist/agent-src/rules/augment-edit-discipline.md +3 -5
- package/dist/agent-src/rules/autonomous-execution.md +3 -5
- package/dist/agent-src/rules/brand-consistency.md +3 -5
- package/dist/agent-src/rules/brand-source-of-truth.md +3 -5
- package/dist/agent-src/rules/cli-output-handling.md +4 -6
- package/dist/agent-src/rules/command-suggestion-policy.md +3 -5
- package/dist/agent-src/rules/commit-conventions.md +3 -5
- package/dist/agent-src/rules/commit-policy.md +8 -10
- package/dist/agent-src/rules/content-quoting-floor.md +88 -0
- package/dist/agent-src/rules/context-hygiene.md +3 -5
- package/dist/agent-src/rules/copilot-routing.md +4 -6
- package/dist/agent-src/rules/decision-revisit-gate.md +120 -0
- package/dist/agent-src/rules/delegation-policy.md +10 -6
- package/dist/agent-src/rules/design-fidelity.md +3 -5
- package/dist/agent-src/rules/devcontainer-routing.md +4 -6
- package/dist/agent-src/rules/direct-answers.md +13 -17
- package/dist/agent-src/rules/docker-commands.md +3 -5
- package/dist/agent-src/rules/domain-adoption-policy.md +3 -5
- package/dist/agent-src/rules/domain-safety-disclaimer.md +3 -5
- package/dist/agent-src/rules/domain-safety-pii.md +7 -8
- package/dist/agent-src/rules/domain-safety-retention.md +3 -5
- package/dist/agent-src/rules/downstream-changes.md +3 -4
- package/dist/agent-src/rules/engineering-safety-floor.md +3 -5
- package/dist/agent-src/rules/external-reference-deep-dive.md +3 -5
- package/dist/agent-src/rules/fast-path-marker-visibility.md +3 -5
- package/dist/agent-src/rules/finance-safety-floor.md +3 -6
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -5
- package/dist/agent-src/rules/git-history-discipline.md +3 -5
- package/dist/agent-src/rules/guidelines.md +2 -4
- package/dist/agent-src/rules/icon-consistency.md +4 -5
- package/dist/agent-src/rules/image-likeness-and-rights.md +3 -5
- package/dist/agent-src/rules/improve-before-implement.md +5 -5
- package/dist/agent-src/rules/invite-challenge.md +3 -5
- package/dist/agent-src/rules/language-and-tone.md +13 -15
- package/dist/agent-src/rules/laravel-routing.md +3 -5
- package/dist/agent-src/rules/laravel-translations.md +3 -5
- package/dist/agent-src/rules/legal-safety-floor.md +5 -7
- package/dist/agent-src/rules/lethal-trifecta-guard.md +3 -5
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +4 -7
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +3 -5
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +2 -4
- package/dist/agent-src/rules/media-governance-routing.md +3 -5
- package/dist/agent-src/rules/media-sync-ground-truth.md +3 -5
- package/dist/agent-src/rules/minimal-safe-diff.md +5 -5
- package/dist/agent-src/rules/missing-tool-handling.md +3 -5
- package/dist/agent-src/rules/model-recommendation.md +4 -6
- package/dist/agent-src/rules/no-attribution-footers.md +3 -5
- package/dist/agent-src/rules/no-cheap-questions.md +5 -8
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +3 -6
- package/dist/agent-src/rules/no-pr-progress-comments.md +3 -6
- package/dist/agent-src/rules/no-roadmap-references.md +3 -5
- package/dist/agent-src/rules/non-destructive-by-default.md +11 -13
- package/dist/agent-src/rules/notes-first-reasoning.md +3 -5
- package/dist/agent-src/rules/onboarding-gate.md +4 -6
- package/dist/agent-src/rules/output-discipline.md +3 -5
- package/dist/agent-src/rules/package-ci-checks.md +3 -5
- package/dist/agent-src/rules/persona-governance.md +2 -4
- package/dist/agent-src/rules/php-coding.md +3 -5
- package/dist/agent-src/rules/preservation-guard.md +2 -4
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -5
- package/dist/agent-src/rules/reviewer-awareness.md +5 -6
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +3 -5
- package/dist/agent-src/rules/roadmap-progress-sync.md +5 -5
- package/dist/agent-src/rules/role-mode-adherence.md +2 -4
- package/dist/agent-src/rules/rule-type-governance.md +3 -5
- package/dist/agent-src/rules/runtime-safety.md +2 -4
- package/dist/agent-src/rules/scope-control.md +10 -11
- package/dist/agent-src/rules/security-sensitive-stop.md +4 -5
- package/dist/agent-src/rules/size-enforcement.md +2 -4
- package/dist/agent-src/rules/skill-improvement-trigger.md +3 -5
- package/dist/agent-src/rules/skill-quality.md +3 -5
- package/dist/agent-src/rules/slash-command-routing-policy.md +3 -5
- package/dist/agent-src/rules/source-confidentiality.md +3 -5
- package/dist/agent-src/rules/source-discovery-gate.md +3 -5
- package/dist/agent-src/rules/source-of-truth.md +3 -5
- package/dist/agent-src/rules/strategy-safety-floor.md +3 -5
- package/dist/agent-src/rules/symfony-routing.md +4 -6
- package/dist/agent-src/rules/telegraph-speak.md +4 -5
- package/dist/agent-src/rules/think-before-action.md +7 -4
- package/dist/agent-src/rules/token-budget-discipline.md +29 -5
- package/dist/agent-src/rules/token-efficiency.md +3 -5
- package/dist/agent-src/rules/token-optimizer-maintenance.md +3 -5
- package/dist/agent-src/rules/tool-safety.md +2 -4
- package/dist/agent-src/rules/ui-audit-gate.md +3 -6
- package/dist/agent-src/rules/untrusted-input-defense.md +11 -10
- package/dist/agent-src/rules/upstream-proposal.md +4 -6
- package/dist/agent-src/rules/user-interaction.md +7 -5
- package/dist/agent-src/rules/user-interrupt-priority.md +17 -8
- package/dist/agent-src/rules/verify-before-complete.md +12 -22
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +3 -3
- package/dist/agent-src/scripts/update_roadmap_progress.ts +197 -7
- package/dist/agent-src/skills/adr-create/SKILL.md +52 -42
- package/dist/agent-src/skills/adversarial-review/SKILL.md +1 -1
- package/dist/agent-src/skills/agent-docs-writing/SKILL.md +18 -0
- package/dist/agent-src/skills/agent-security-review/SKILL.md +1 -1
- package/dist/agent-src/skills/ai-council/SKILL.md +14 -1
- package/dist/agent-src/skills/blade-ui/SKILL.md +4 -0
- package/dist/agent-src/skills/blameless-post-mortem/SKILL.md +0 -3
- package/dist/agent-src/skills/brand/SKILL.md +1 -1
- package/dist/agent-src/skills/brand-identity/SKILL.md +3 -3
- package/dist/agent-src/skills/brand-strategy/SKILL.md +1 -1
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +5 -4
- package/dist/agent-src/skills/canvas-design/SKILL.md +6 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +7 -4
- package/dist/agent-src/skills/code-review/SKILL.md +5 -0
- package/dist/agent-src/skills/complexity-first-planning/SKILL.md +6 -5
- package/dist/agent-src/skills/condense-memory/SKILL.md +11 -11
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/context-document/SKILL.md +17 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -3
- package/dist/agent-src/skills/decision-record/SKILL.md +6 -0
- package/dist/agent-src/skills/decision-review/SKILL.md +5 -3
- package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +6 -1
- package/dist/agent-src/skills/design-intelligence/SKILL.md +45 -2
- package/dist/agent-src/skills/design-intelligence/references/design-languages.md +1 -1
- package/dist/agent-src/skills/design-review/SKILL.md +23 -11
- package/dist/agent-src/skills/design-system-capture/SKILL.md +41 -0
- package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +62 -0
- package/dist/agent-src/skills/design-tokens/SKILL.md +11 -4
- package/dist/agent-src/skills/design-variations/SKILL.md +127 -0
- package/dist/agent-src/skills/design-variations/evals/triggers.json +17 -0
- package/dist/agent-src/skills/emit-tickets/SKILL.md +4 -4
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +6 -0
- package/dist/agent-src/skills/fe-design/SKILL.md +20 -0
- package/dist/agent-src/skills/flux/SKILL.md +4 -0
- package/dist/agent-src/skills/html-deck/SKILL.md +123 -0
- package/dist/agent-src/skills/html-deck/evals/triggers.json +17 -0
- package/dist/agent-src/skills/html-deck/templates/deck-shell.html +77 -0
- package/dist/agent-src/skills/iconography/SKILL.md +1 -0
- package/dist/agent-src/skills/image-editing/evals/triggers.json +13 -13
- package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +136 -0
- package/dist/agent-src/skills/judge-artifact-completeness/calibration/fixtures.json +149 -0
- package/dist/agent-src/skills/judge-artifact-completeness/evals/triggers.json +17 -0
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/architecture-score.json +73 -0
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/pr-review-score.json +65 -0
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/roadmap-score.json +73 -0
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +73 -0
- package/dist/agent-src/skills/judge-code-quality/SKILL.md +1 -0
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +99 -0
- package/dist/agent-src/skills/judge-injection-defense/calibration/fixtures.json +24 -0
- package/dist/agent-src/skills/judge-injection-defense/evals/triggers.json +17 -0
- package/dist/agent-src/skills/judge-injection-defense/fixtures/behavioral-fixtures.json +63 -0
- package/dist/agent-src/skills/judge-injection-defense/fixtures/coverage-report.md +53 -0
- package/dist/agent-src/skills/judge-injection-defense/fixtures/perturbation-taxonomy.json +110 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +134 -0
- package/dist/agent-src/skills/judge-synthesis/evals/triggers.json +17 -0
- package/dist/agent-src/skills/laravel/SKILL.md +0 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +46 -0
- package/dist/agent-src/skills/lint-skills/SKILL.md +6 -6
- package/dist/agent-src/skills/logo-generation/SKILL.md +1 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
- package/dist/agent-src/skills/md-language-check/SKILL.md +3 -3
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +66 -1
- package/dist/agent-src/skills/migration-architect/SKILL.md +1 -0
- package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +2 -2
- package/dist/agent-src/skills/performance-analysis/SKILL.md +2 -0
- package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +4 -4
- package/dist/agent-src/skills/premortem/SKILL.md +0 -3
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +16 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +18 -0
- package/dist/agent-src/skills/react-shadcn-ui/reference/registry.md +59 -0
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +3 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +5 -1
- package/dist/agent-src/skills/release-comms/SKILL.md +47 -46
- package/dist/agent-src/skills/roadmap-management/SKILL.md +25 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +33 -3
- package/dist/agent-src/skills/root-cause-frameworks/SKILL.md +0 -3
- package/dist/agent-src/skills/script-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/security-audit/SKILL.md +1 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +4 -0
- package/dist/agent-src/skills/source-discovery/SKILL.md +22 -3
- package/dist/agent-src/skills/sql-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +33 -14
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +11 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-steps.md +8 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +30 -1
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +4 -0
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +2 -2
- package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
- package/dist/agent-src/skills/typography-system/SKILL.md +4 -3
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -0
- package/dist/agent-src/skills/wireframe/SKILL.md +118 -0
- package/dist/agent-src/skills/wireframe/evals/triggers.json +17 -0
- package/dist/agent-src/templates/agent-settings.md +22 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/command.md +2 -2
- package/dist/agent-src/templates/contexts/knowledge-pages.md +116 -0
- package/dist/agent-src/templates/hooks/pre-commit-frontmatter +1 -1
- package/dist/agent-src/templates/roadmaps.md +70 -2
- package/dist/agent-src/templates/rule.md +1 -1
- package/dist/agent-src/templates/scripts/README.md +3 -3
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +109 -0
- package/dist/agent-src/templates/tickets.md +8 -8
- package/dist/cli/commands/recordTriggerEval.test.js +1 -1
- package/dist/cli/commands/recordTriggerEval.test.js.map +1 -1
- package/dist/cli/initRouting.js +4 -2
- package/dist/cli/initRouting.js.map +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +802 -258
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +8 -8
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +46 -28
- package/dist/discovery/trust-report.md +12 -11
- package/dist/discovery/workspaces.json +32 -18
- package/dist/install/preflight.js +173 -0
- package/dist/install/preflight.js.map +1 -0
- package/dist/mcp/registry-manifest.json +4 -4
- package/dist/router.json +1 -1
- package/dist/server/routes/settings.js +4 -0
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/schemas/settings.js +6 -1
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/CLAIMS.md +108 -0
- package/docs/MIGRATION.md +3 -3
- package/docs/architecture.md +6 -6
- package/docs/benchmark.md +133 -2
- package/docs/benchmark.pinned.yml +31 -0
- package/docs/capability-matrix.md +1 -0
- package/docs/catalog.md +92 -74
- package/docs/command-flows.md +16 -4
- package/docs/comparison.yaml +35 -0
- package/docs/contracts/agents-layout.md +148 -0
- package/docs/contracts/brand-token-consumption.md +5 -0
- package/docs/contracts/capability-boundary.md +5 -0
- package/docs/contracts/command-category-governance.md +5 -0
- package/docs/contracts/command-clusters.md +1 -0
- package/docs/contracts/command-surface-tiers.md +1 -1
- package/docs/contracts/conformance.md +84 -0
- package/docs/contracts/creative-pack-boundary.md +5 -0
- package/docs/contracts/discovery-manifest.schema.json +5 -4
- package/docs/contracts/file-ownership-matrix.json +4605 -985
- package/docs/contracts/governance-enforcement-projection.md +5 -0
- package/docs/contracts/gui-wizard.md +1 -1
- package/docs/contracts/hook-architecture-v1.md +2 -2
- package/docs/contracts/implement-ticket-flow.md +1 -1
- package/docs/contracts/kernel-membership.md +13 -0
- package/docs/contracts/mcp-tool-inventory.md +23 -23
- package/docs/contracts/no-runtime-boundary.md +6 -1
- package/docs/contracts/review-lens-schema.md +5 -0
- package/docs/contracts/rule-router.md +102 -8
- package/docs/contracts/skill-bundled-assets.md +1 -1
- package/docs/contracts/skill-dry-run.md +1 -1
- package/docs/contracts/subagent-boundary.md +5 -0
- package/docs/contracts/ticket-bundle-format.md +9 -4
- package/docs/contracts/tier-3-contrib-plugin.md +2 -2
- package/docs/contracts/write-engine.md +3 -0
- package/docs/customization.md +87 -15
- package/docs/decisions/ADR-107-legal-domain-pack-adoption.md +1 -1
- package/docs/decisions/ADR-109-subagent-v1-contract.md +246 -0
- package/docs/decisions/ADR-110-discipline-profile-resolution-locus.md +105 -0
- package/docs/decisions/INDEX.md +2 -0
- package/docs/distribution/awesome-list-submission.md +46 -0
- package/docs/distribution/launch-story-draft.md +58 -0
- package/docs/end-to-end-walkthroughs.md +2 -2
- package/docs/getting-started.md +2 -2
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +24 -0
- package/docs/guidelines/agent-infra/corpus-grounding-authoring.md +1 -1
- package/docs/guidelines/agent-infra/linked-projects-onboarding-gate.md +2 -2
- package/docs/guidelines/agent-infra/missing-tool-handling.md +3 -3
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
- package/docs/guidelines/augment-portability-patterns.md +1 -1
- package/docs/guidelines/code-clarity.md +19 -0
- package/docs/guidelines/design-antipatterns-triggers.json +2 -1
- package/docs/guidelines/design-antipatterns.md +35 -0
- package/docs/guidelines/design-canon.md +62 -0
- package/docs/guidelines/design-modes.md +6 -0
- package/docs/guidelines/php/general.md +9 -1
- package/docs/guidelines/php/php-coding-patterns.md +7 -0
- package/docs/guides/cross-repo-retrieval.md +1 -1
- package/docs/guides/frontend-design-corpus-refresh.md +2 -2
- package/docs/guides/local-analytics.md +4 -4
- package/docs/guides/skill-discovery.md +1 -1
- package/docs/guides/skill-preview.md +1 -1
- package/docs/hook-payload-capture.md +6 -6
- package/docs/install-friction-report.md +66 -0
- package/docs/installation.md +1 -1
- package/docs/maintainers/optional-media-deps.md +50 -0
- package/docs/mcp-server.md +11 -12
- package/docs/media/proof-demo.cast +14 -0
- package/docs/media/proof-demo.gif +0 -0
- package/docs/migration/consumer-template-consumption-model.md +1 -1
- package/docs/migration/divergences/bench-stats-float-precision.md +1 -1
- package/docs/migration/node-floor.md +1 -1
- package/docs/migration/yaml-roundtrip-spike.md +1 -1
- package/docs/personas.md +16 -5
- package/docs/positioning-evidence.md +86 -0
- package/docs/proof.md +86 -0
- package/docs/skills-catalog.md +1 -1
- package/docs/troubleshooting.md +8 -8
- package/docs/wedge/production-validator/README.md +57 -0
- package/docs/wedge/production-validator/production-validator.md +56 -0
- package/docs/wizard.md +2 -2
- package/package.json +1 -1
- package/src/config/agent-settings.template.yml +71 -4
- package/src/config/agents-paths.yml +254 -0
- package/src/config/budgets.yml +16 -0
- package/src/config/discovery/packs.yml +1 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/gitignore-block.txt +25 -0
- package/src/config/host-capabilities.yml +31 -0
- package/src/config/profiles/balanced.ini +4 -0
- package/src/config/profiles/full.ini +4 -0
- package/src/config/profiles/minimal.ini +4 -0
- package/src/scripts/_cli/cmd_conformance.ts +716 -0
- package/src/scripts/_cli/cmd_doctor.ts +23 -2
- package/src/scripts/_cli/cmd_fleet.ts +401 -0
- package/src/scripts/_cli/cmd_preflight.ts +159 -0
- package/src/scripts/_dispatch.bash +10 -0
- package/src/scripts/_lib/knowledge_events.ts +193 -0
- package/src/scripts/_lib/subagent_steering.ts +115 -3
- package/src/scripts/_lib/text_similarity.ts +75 -0
- package/src/scripts/ai-video/test-pipeline.sh +1 -1
- package/src/scripts/ai_council/clients.ts +19 -3
- package/src/scripts/append_contested.ts +112 -0
- package/src/scripts/audit_auto_rules.ts +11 -1
- package/src/scripts/audit_mcp_tools.ts +25 -11
- package/src/scripts/bench_ab_v2_run.ts +527 -40
- package/src/scripts/bench_ab_v2_stats.ts +6 -0
- package/src/scripts/bench_matrix.ts +266 -0
- package/src/scripts/bootstrap_knowledge.ts +267 -0
- package/src/scripts/build_discovery_manifest.ts +42 -2
- package/src/scripts/build_proof.ts +214 -0
- package/src/scripts/check_always_budget.ts +3 -0
- package/src/scripts/check_augment_description_cap.ts +2 -2
- package/src/scripts/check_claims.ts +270 -0
- package/src/scripts/check_comparison.ts +79 -0
- package/src/scripts/check_generated_artefact_headers.ts +109 -0
- package/src/scripts/check_generator_output_coverage.ts +142 -0
- package/src/scripts/check_gitignore_freshness.ts +127 -0
- package/src/scripts/check_knowledge_pages.ts +210 -0
- package/src/scripts/check_knowledge_sharing.ts +162 -0
- package/src/scripts/check_media_deps.ts +91 -0
- package/src/scripts/check_memory_contradiction.ts +280 -0
- package/src/scripts/check_memory_similarity.ts +134 -0
- package/src/scripts/check_quality_regression.ts +56 -10
- package/src/scripts/check_references.ts +3 -1
- package/src/scripts/check_release_pr_shape.ts +4 -0
- package/src/scripts/check_site_links.ts +135 -0
- package/src/scripts/check_skill_gaps.ts +99 -0
- package/src/scripts/check_token_quality_golden.ts +197 -11
- package/src/scripts/check_tracked_but_ignored.ts +67 -0
- package/src/scripts/cluster_near_miss_patterns.ts +0 -0
- package/src/scripts/compile_router.ts +30 -3
- package/src/scripts/condense.ts +350 -14
- package/src/scripts/consolidate_knowledge_events.ts +192 -0
- package/src/scripts/degrade_to_pointer.ts +136 -0
- package/src/scripts/design_slop_rules.test.ts +208 -0
- package/src/scripts/design_slop_rules.ts +530 -0
- package/src/scripts/emit_knowledge_event.ts +158 -0
- package/src/scripts/export_replay_corpus.ts +187 -0
- package/src/scripts/external_sources_denylist.json +14 -3
- package/src/scripts/fold_intake.ts +281 -0
- package/src/scripts/generate_capability_matrix.ts +9 -1
- package/src/scripts/generate_knowledge_index.ts +222 -0
- package/src/scripts/hook_manifest.yaml +40 -17
- package/src/scripts/hooks/design_slop_hook.ts +181 -0
- package/src/scripts/hooks/dispatch_hook.ts +18 -0
- package/src/scripts/hot_context_hook.ts +372 -0
- package/src/scripts/install +47 -0
- package/src/scripts/install-hooks.sh +17 -0
- package/src/scripts/inventory_meta_layers.ts +11 -0
- package/src/scripts/janitor.ts +258 -0
- package/src/scripts/lint_agent_security.ts +1 -0
- package/src/scripts/lint_agents_layout.ts +74 -15
- package/src/scripts/lint_bench_ab.ts +4 -1
- package/src/scripts/lint_confusables.ts +197 -0
- package/src/scripts/lint_design_slop.ts +245 -0
- package/src/scripts/lint_featured_skills.ts +0 -0
- package/src/scripts/lint_framework_leakage_allowlist.json +26 -3
- package/src/scripts/lint_knowledge_scale.ts +250 -0
- package/src/scripts/lint_legal_pack.ts +67 -0
- package/src/scripts/lint_persona_governance.ts +8 -3
- package/src/scripts/lint_regression.ts +15 -0
- package/src/scripts/lint_roadmap_blockers.ts +202 -0
- package/src/scripts/lint_roadmap_complexity.ts +81 -2
- package/src/scripts/lint_subagent_determinism.ts +125 -0
- package/src/scripts/measure_augment_budget.ts +46 -6
- package/src/scripts/measure_patterns.ts +4 -3
- package/src/scripts/measure_skill_reduction.ts +6 -6
- package/src/scripts/migration_status.ts +6 -2
- package/src/scripts/mine_missing_guardrails.ts +189 -0
- package/src/scripts/parity/phase_gate.ts +1 -1
- package/src/scripts/parity/replay.ts +21 -0
- package/src/scripts/project_thin_rules.ts +120 -16
- package/src/scripts/release.ts +39 -1
- package/src/scripts/render_benchmark_composite.ts +378 -0
- package/src/scripts/roadmap_progress_hook.ts +101 -43
- package/src/scripts/schemas/skill.schema.json +27 -0
- package/src/scripts/schemas/subagent.schema.json +106 -0
- package/src/scripts/skill_linter.ts +1 -0
- package/src/scripts/smoke/kernel.sh +5 -4
- package/src/scripts/surface-tiers.yml +1 -0
- package/src/scripts/sync_gitignore.ts +4 -0
- package/src/scripts/update_skill_candidates.ts +172 -0
- package/src/scripts/validate_frontmatter.ts +1 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lint_design_slop — deterministic anti-slop DETECTOR for consumer projects.
|
|
4
|
+
*
|
|
5
|
+
* The aesthetic-PROVENANCE layer that `lint_design_quality` deliberately omits.
|
|
6
|
+
* It scans HTML/CSS/JSX/Markdown for the "AI tells" catalogued in
|
|
7
|
+
* `docs/guidelines/design-antipatterns.md` and emits structured findings
|
|
8
|
+
* (rule-id + catalog-id + severity P0–P3 + file:line). The rule registry lives
|
|
9
|
+
* in `design_slop_rules.ts`.
|
|
10
|
+
*
|
|
11
|
+
* FLAGS, NEVER A HARD BLOCK. Default exit is 0 regardless of findings — slop
|
|
12
|
+
* tells are rebuttable presumptions, not failures. CI opts into failing with
|
|
13
|
+
* `--fail-on <P0|P1|P2|P3>` (fails when any finding at or above that severity
|
|
14
|
+
* remains). This honours the council 2026-06-28 "flags not blocks" verdict.
|
|
15
|
+
*
|
|
16
|
+
* Zero runtime token cost: this runs in Node (CI / pre-commit / optional hook),
|
|
17
|
+
* never in the model's context. `design-review` cites the structured `--json`
|
|
18
|
+
* output instead of reloading the 12 KB prose catalog.
|
|
19
|
+
*
|
|
20
|
+
* Dependency-free pattern analysis (no postcss/@babel) — see the design note in
|
|
21
|
+
* design_slop_rules.ts. Same posture as lint_design_quality.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* npx tsx lint_design_slop.ts --dir src/ [--json] [--fail-on P1] [--quiet]
|
|
25
|
+
*
|
|
26
|
+
* Context gate: a consumer DESIGN.md (project root or scan dir) that declares a
|
|
27
|
+
* pattern as intentional suppresses the matching rule (e.g. "warm-neutral" →
|
|
28
|
+
* C5 cream-palette is not flagged). Inline-ignore (eslint-style):
|
|
29
|
+
* design-slop-disable <rule-id> (file scope, top of file)
|
|
30
|
+
* design-slop-disable-next-line <rule-id>
|
|
31
|
+
* design-slop-disable-line <rule-id>
|
|
32
|
+
* Per-project config (.design-quality.json, shared with lint_design_quality):
|
|
33
|
+
* { "ignoreRules": ["slop-c5-cream-palette"], "ignoreFiles": ["src/legacy/**"] }
|
|
34
|
+
*
|
|
35
|
+
* Exit codes: 0 = clean OR findings-below-threshold, 2 = findings at/above
|
|
36
|
+
* --fail-on threshold, 1 = internal error.
|
|
37
|
+
*/
|
|
38
|
+
import fs from "node:fs";
|
|
39
|
+
import path from "node:path";
|
|
40
|
+
import {
|
|
41
|
+
SLOP_RULES,
|
|
42
|
+
type DesignContext,
|
|
43
|
+
type Engine,
|
|
44
|
+
type Severity,
|
|
45
|
+
} from "./design_slop_rules.js";
|
|
46
|
+
|
|
47
|
+
interface Finding {
|
|
48
|
+
rule: string;
|
|
49
|
+
catalogId: string;
|
|
50
|
+
severity: Severity;
|
|
51
|
+
file: string;
|
|
52
|
+
line: number;
|
|
53
|
+
snippet: string;
|
|
54
|
+
message: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface ProjectConfig {
|
|
58
|
+
ignoreRules?: string[];
|
|
59
|
+
ignoreFiles?: string[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const SEVERITY_ORDER: Severity[] = ["P3", "P2", "P1", "P0"];
|
|
63
|
+
const sevRank = (s: Severity): number => SEVERITY_ORDER.indexOf(s);
|
|
64
|
+
|
|
65
|
+
// ext → which engine-classes a file of that type can contain
|
|
66
|
+
function enginesForExt(ext: string): Set<Engine> {
|
|
67
|
+
if (/\.(css|scss|sass|less)$/i.test(ext)) return new Set<Engine>(["css"]);
|
|
68
|
+
if (/\.(html|htm|vue|svelte|astro)$/i.test(ext)) return new Set<Engine>(["css", "html", "copy"]);
|
|
69
|
+
if (/\.(jsx|tsx)$/i.test(ext)) return new Set<Engine>(["css", "jsx", "copy"]);
|
|
70
|
+
if (/\.(md|mdx)$/i.test(ext)) return new Set<Engine>(["copy"]);
|
|
71
|
+
return new Set<Engine>();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function* walkDir(dir: string, ext: RegExp): Generator<string> {
|
|
75
|
+
if (!fs.existsSync(dir)) return;
|
|
76
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
77
|
+
const full = path.join(dir, entry.name);
|
|
78
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
79
|
+
if (entry.isDirectory()) yield* walkDir(full, ext);
|
|
80
|
+
else if (ext.test(entry.name)) yield full;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function loadConfig(dir: string): ProjectConfig {
|
|
85
|
+
const p = path.join(dir, ".design-quality.json");
|
|
86
|
+
if (!fs.existsSync(p)) return {};
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(fs.readFileSync(p, "utf-8")) as ProjectConfig;
|
|
89
|
+
} catch {
|
|
90
|
+
return {};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Read DESIGN.md (scan dir, then project root) as the context-gate source. */
|
|
95
|
+
export function loadDesignContext(scanDir: string): DesignContext {
|
|
96
|
+
const candidates = [
|
|
97
|
+
path.join(scanDir, "DESIGN.md"),
|
|
98
|
+
path.join(process.cwd(), "DESIGN.md"),
|
|
99
|
+
path.join(scanDir, "..", "DESIGN.md"),
|
|
100
|
+
];
|
|
101
|
+
let raw = "";
|
|
102
|
+
for (const c of candidates) {
|
|
103
|
+
if (fs.existsSync(c)) {
|
|
104
|
+
raw = fs.readFileSync(c, "utf-8").toLowerCase();
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
raw,
|
|
110
|
+
has: (...keywords: string[]) => keywords.some((k) => raw.includes(k.toLowerCase())),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function parseIgnores(lines: string[]): Map<string, Set<number>> {
|
|
115
|
+
const ignores = new Map<string, Set<number>>();
|
|
116
|
+
const add = (rule: string, line: number) => {
|
|
117
|
+
const set = ignores.get(rule) ?? new Set<number>();
|
|
118
|
+
set.add(line);
|
|
119
|
+
ignores.set(rule, set);
|
|
120
|
+
};
|
|
121
|
+
for (let i = 0; i < lines.length; i++) {
|
|
122
|
+
const line = lines[i] ?? "";
|
|
123
|
+
const file = /design-slop-disable\s+([\w-]+)/i.exec(line);
|
|
124
|
+
if (file && file[1] && !/-line|-next-line/.test(line)) {
|
|
125
|
+
ignores.set(file[1].toLowerCase(), new Set([...Array(99999).keys()].map((n) => n + 1)));
|
|
126
|
+
}
|
|
127
|
+
const next = /design-slop-disable-next-line\s+([\w-]+)/i.exec(line);
|
|
128
|
+
if (next && next[1]) add(next[1].toLowerCase(), i + 2);
|
|
129
|
+
const cur = /design-slop-disable-line\s+([\w-]+)/i.exec(line);
|
|
130
|
+
if (cur && cur[1]) add(cur[1].toLowerCase(), i + 1);
|
|
131
|
+
}
|
|
132
|
+
return ignores;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function scanFile(
|
|
136
|
+
content: string,
|
|
137
|
+
relPath: string,
|
|
138
|
+
ctx: DesignContext,
|
|
139
|
+
): Finding[] {
|
|
140
|
+
const lines = content.split("\n");
|
|
141
|
+
const ext = path.extname(relPath).toLowerCase();
|
|
142
|
+
const fileEngines = enginesForExt(ext);
|
|
143
|
+
if (fileEngines.size === 0) return [];
|
|
144
|
+
const ignores = parseIgnores(lines);
|
|
145
|
+
|
|
146
|
+
const out: Finding[] = [];
|
|
147
|
+
for (const rule of SLOP_RULES) {
|
|
148
|
+
if (!rule.engines.some((e) => fileEngines.has(e))) continue;
|
|
149
|
+
if (rule.gated && rule.gated(ctx)) continue; // DESIGN.md declares intent → suppress
|
|
150
|
+
let hits;
|
|
151
|
+
try {
|
|
152
|
+
hits = rule.detect({ content, lines, ext, ctx });
|
|
153
|
+
} catch {
|
|
154
|
+
continue; // a single rule throwing never kills the scan
|
|
155
|
+
}
|
|
156
|
+
for (const h of hits) {
|
|
157
|
+
const ruleIgnore = ignores.get(rule.id.toLowerCase());
|
|
158
|
+
if (ruleIgnore && ruleIgnore.has(h.line)) continue;
|
|
159
|
+
out.push({
|
|
160
|
+
rule: rule.id,
|
|
161
|
+
catalogId: rule.catalogId,
|
|
162
|
+
severity: rule.severity,
|
|
163
|
+
file: relPath,
|
|
164
|
+
line: h.line,
|
|
165
|
+
snippet: h.snippet,
|
|
166
|
+
message: rule.message,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function main(): void {
|
|
174
|
+
const args = process.argv.slice(2);
|
|
175
|
+
const jsonMode = args.includes("--json");
|
|
176
|
+
const quiet = args.includes("--quiet");
|
|
177
|
+
const dirIdx = args.indexOf("--dir");
|
|
178
|
+
const scanDir = dirIdx >= 0 && args[dirIdx + 1] ? path.resolve(args[dirIdx + 1]!) : path.resolve(process.cwd(), "src");
|
|
179
|
+
const failIdx = args.indexOf("--fail-on");
|
|
180
|
+
const failOn = (failIdx >= 0 ? args[failIdx + 1] : undefined) as Severity | undefined;
|
|
181
|
+
|
|
182
|
+
if (!fs.existsSync(scanDir)) {
|
|
183
|
+
if (!quiet) {
|
|
184
|
+
process.stderr.write(`[lint_design_slop] scan directory not found: ${scanDir}\n`);
|
|
185
|
+
process.stderr.write("Opt-in for consumer projects. Run with --dir <path> at your UI source.\n");
|
|
186
|
+
}
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const ctx = loadDesignContext(scanDir);
|
|
191
|
+
const config = loadConfig(process.cwd());
|
|
192
|
+
const ignoreRules = new Set((config.ignoreRules ?? []).map((r) => r.toLowerCase()));
|
|
193
|
+
const ignoreGlobs = config.ignoreFiles ?? [];
|
|
194
|
+
|
|
195
|
+
const files: string[] = [];
|
|
196
|
+
for (const f of walkDir(scanDir, /\.(html|htm|css|scss|sass|less|vue|svelte|astro|jsx|tsx|md|mdx)$/i)) {
|
|
197
|
+
if (!ignoreGlobs.some((g) => f.includes(g.replace("**", "")))) files.push(f);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const findings: Finding[] = [];
|
|
201
|
+
for (const fp of files) {
|
|
202
|
+
const rel = path.relative(process.cwd(), fp);
|
|
203
|
+
try {
|
|
204
|
+
const fileFindings = scanFile(fs.readFileSync(fp, "utf-8"), rel, ctx).filter(
|
|
205
|
+
(f) => !ignoreRules.has(f.rule.toLowerCase()),
|
|
206
|
+
);
|
|
207
|
+
findings.push(...fileFindings);
|
|
208
|
+
} catch (err) {
|
|
209
|
+
if (!quiet) process.stderr.write(`[lint_design_slop] error: ${fp}: ${err}\n`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
findings.sort((a, b) => sevRank(b.severity) - sevRank(a.severity));
|
|
214
|
+
|
|
215
|
+
const overThreshold = failOn
|
|
216
|
+
? findings.filter((f) => sevRank(f.severity) >= sevRank(failOn))
|
|
217
|
+
: [];
|
|
218
|
+
|
|
219
|
+
if (jsonMode) {
|
|
220
|
+
process.stdout.write(JSON.stringify({ findings, failOn: failOn ?? null, overThreshold: overThreshold.length }, null, 2) + "\n");
|
|
221
|
+
process.exit(overThreshold.length > 0 ? 2 : 0);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (findings.length === 0) {
|
|
225
|
+
if (!quiet) process.stdout.write(`✅ lint_design_slop: no anti-slop tells in ${files.length} file(s).\n`);
|
|
226
|
+
process.exit(0);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const f of findings) {
|
|
230
|
+
const icon = f.severity === "P0" || f.severity === "P1" ? "⚠️ " : "•";
|
|
231
|
+
process.stdout.write(`${icon} [${f.severity} ${f.catalogId}] ${f.file}:${f.line} (${f.rule}) — ${f.message}\n ${f.snippet}\n`);
|
|
232
|
+
}
|
|
233
|
+
process.stdout.write(
|
|
234
|
+
`\nlint_design_slop: ${findings.length} tell(s) flagged (rebuttable — declare intent in DESIGN.md, ` +
|
|
235
|
+
`design-slop-disable-next-line <rule>, or .design-quality.json).` +
|
|
236
|
+
(failOn ? ` ${overThreshold.length} at/above ${failOn}.` : " Flags only; no CI failure (pass --fail-on to gate).") +
|
|
237
|
+
"\n",
|
|
238
|
+
);
|
|
239
|
+
process.exit(overThreshold.length > 0 ? 2 : 0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Run only when invoked directly (not when imported by the test guard).
|
|
243
|
+
const invokedDirectly =
|
|
244
|
+
process.argv[1] !== undefined && /lint_design_slop\.ts$/.test(process.argv[1]);
|
|
245
|
+
if (invokedDirectly) main();
|
|
Binary file
|
|
@@ -480,7 +480,7 @@
|
|
|
480
480
|
{
|
|
481
481
|
"file": ".agent-src.uncondensed/rules/architecture.md",
|
|
482
482
|
"lines": [
|
|
483
|
-
|
|
483
|
+
69
|
|
484
484
|
],
|
|
485
485
|
"reason": "Multi-framework module-system enumeration (Laravel, Turborepo, NestJS, Go) — comparative example, no project mandate"
|
|
486
486
|
},
|
|
@@ -515,14 +515,14 @@
|
|
|
515
515
|
{
|
|
516
516
|
"file": ".agent-src.uncondensed/rules/architecture.md",
|
|
517
517
|
"lines": [
|
|
518
|
-
|
|
518
|
+
74
|
|
519
519
|
],
|
|
520
520
|
"reason": "Single Laravel-shape example showing how `{module_root}/*/{agent_folder}/` resolves on a Laravel HMVC project (road-to-configurable-modules Phase D)"
|
|
521
521
|
},
|
|
522
522
|
{
|
|
523
523
|
"file": ".agent-src.uncondensed/rules/roadmap-ci-steps-policy.md",
|
|
524
524
|
"lines": [
|
|
525
|
-
|
|
525
|
+
99
|
|
526
526
|
],
|
|
527
527
|
"reason": "Single Laravel-shape example showing module-scoped roadmap path (road-to-configurable-modules Phase D)"
|
|
528
528
|
},
|
|
@@ -598,6 +598,29 @@
|
|
|
598
598
|
29
|
|
599
599
|
],
|
|
600
600
|
"reason": "Cross-stack UI-stack enumeration (React, Blade, Tailwind)"
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"file": "src/skills/code-review/SKILL.md",
|
|
604
|
+
"lines": [
|
|
605
|
+
79,
|
|
606
|
+
88,
|
|
607
|
+
90
|
|
608
|
+
],
|
|
609
|
+
"reason": "Cross-stack security-review checklist rows naming Laravel/Symfony/NestJS/DTO peers side-by-side (allowed multi-ecosystem documentation, not a mandate)"
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
"file": "src/skills/context-document/SKILL.md",
|
|
613
|
+
"lines": [
|
|
614
|
+
83
|
|
615
|
+
],
|
|
616
|
+
"reason": "Module-path resolution table citing the Laravel shape as one named example next to the generic modules.root_paths mechanism"
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
"file": "src/skills/verify-completion-evidence/SKILL.md",
|
|
620
|
+
"lines": [
|
|
621
|
+
183
|
|
622
|
+
],
|
|
623
|
+
"reason": "Carve-out pointer to the quality-tools skill (the sanctioned one-line handoff shape from framework-neutrality-in-generic-skills)"
|
|
601
624
|
}
|
|
602
625
|
]
|
|
603
626
|
}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Warn-only scale + budget tripwires for the memory/knowledge substrate —
|
|
4
|
+
* road-to-second-brain Phase 0 (council 2026-07-07, see
|
|
5
|
+
* `agents/settings/contexts/second-brain-delta-verdict.md`).
|
|
6
|
+
*
|
|
7
|
+
* These tripwires REPLACE roadmap gates: each warning names its pre-decided
|
|
8
|
+
* activation path, so a firing tripwire is actionable without re-opening the
|
|
9
|
+
* decision. The script never fails the build.
|
|
10
|
+
*
|
|
11
|
+
* Tripwires:
|
|
12
|
+
* - intake scale — `agents/knowledge/intake/events-*.jsonl` > 2000 events
|
|
13
|
+
* → wire `fold_intake.ts` into post-session/CI
|
|
14
|
+
* - sessions scale — `agents/knowledge/sessions/` > 50 pages
|
|
15
|
+
* → design fold-through-consolidate-gate for tracked pages
|
|
16
|
+
* - type scale — any single memory/knowledge type > 200 files
|
|
17
|
+
* → build the pre-decided file-first in-memory BM25 CLI
|
|
18
|
+
* - corpus scale — > 500 files across all types
|
|
19
|
+
* → same BM25 activation path
|
|
20
|
+
* - hot-context size — `agents/runtime/state/hot-context.md` > 600 tokens
|
|
21
|
+
* (estimated at 4 chars/token) → trim schema / fix the
|
|
22
|
+
* deterministic writer
|
|
23
|
+
*
|
|
24
|
+
* Usage: lint_knowledge_scale.ts [--dir <repo-root>] [--format text|json] [--quiet]
|
|
25
|
+
* Exit codes: 0 = ran cleanly (warnings never fail the build), 1 = usage
|
|
26
|
+
* error, 3 = internal error.
|
|
27
|
+
*/
|
|
28
|
+
import * as fs from 'node:fs';
|
|
29
|
+
import * as path from 'node:path';
|
|
30
|
+
import process from 'node:process';
|
|
31
|
+
import { fileURLToPath } from 'node:url';
|
|
32
|
+
|
|
33
|
+
const PROG = 'lint_knowledge_scale.ts';
|
|
34
|
+
|
|
35
|
+
export const INTAKE_EVENTS_MAX = 2000;
|
|
36
|
+
export const SESSIONS_PAGES_MAX = 50;
|
|
37
|
+
export const TYPE_FILES_MAX = 200;
|
|
38
|
+
export const CORPUS_FILES_MAX = 500;
|
|
39
|
+
export const HOT_CONTEXT_TOKENS_MAX = 600;
|
|
40
|
+
export const CHARS_PER_TOKEN = 4;
|
|
41
|
+
|
|
42
|
+
const KNOWLEDGE_TYPED_DIRS = ['sessions', 'concepts', 'procedures', 'decisions'] as const;
|
|
43
|
+
|
|
44
|
+
export interface Warning {
|
|
45
|
+
rule: string;
|
|
46
|
+
metric: string; // "<observed>/<threshold>"
|
|
47
|
+
message: string; // includes the pre-decided activation path
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function listFiles(dir: string, exts: readonly string[]): string[] {
|
|
51
|
+
let entries: fs.Dirent[];
|
|
52
|
+
try {
|
|
53
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
54
|
+
} catch {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
return entries
|
|
58
|
+
.filter((e) => e.isFile() && exts.some((x) => e.name.endsWith(x)))
|
|
59
|
+
.map((e) => path.join(dir, e.name));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function countJsonlLines(file: string): number {
|
|
63
|
+
let text: string;
|
|
64
|
+
try {
|
|
65
|
+
text = fs.readFileSync(file, 'utf-8');
|
|
66
|
+
} catch {
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
return text.split('\n').filter((l) => l.trim().length > 0).length;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Collect per-type file counts across the knowledge + memory substrate. */
|
|
73
|
+
export function collectTypeCounts(root: string): Map<string, number> {
|
|
74
|
+
const counts = new Map<string, number>();
|
|
75
|
+
|
|
76
|
+
// Knowledge cards (flat, top-level *.md except README/INDEX).
|
|
77
|
+
const cardsDir = path.join(root, 'agents', 'knowledge');
|
|
78
|
+
const cards = listFiles(cardsDir, ['.md']).filter((f) => {
|
|
79
|
+
const base = path.basename(f).toLowerCase();
|
|
80
|
+
return base !== 'readme.md' && base !== 'index.md';
|
|
81
|
+
});
|
|
82
|
+
counts.set('knowledge/cards', cards.length);
|
|
83
|
+
|
|
84
|
+
// Lifecycle-typed knowledge dirs.
|
|
85
|
+
for (const d of KNOWLEDGE_TYPED_DIRS) {
|
|
86
|
+
counts.set(`knowledge/${d}`, listFiles(path.join(cardsDir, d), ['.md']).length);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Curated memory types: agents/memory/<type>/ dirs and <type>.yml files.
|
|
90
|
+
// The gitignored per-task scratch (`agents/memory/knowledge/`) is excluded —
|
|
91
|
+
// it is session state, not a curated type.
|
|
92
|
+
const memoryDir = path.join(root, 'agents', 'memory');
|
|
93
|
+
let memEntries: fs.Dirent[] = [];
|
|
94
|
+
try {
|
|
95
|
+
memEntries = fs.readdirSync(memoryDir, { withFileTypes: true });
|
|
96
|
+
} catch {
|
|
97
|
+
// no memory dir — fine
|
|
98
|
+
}
|
|
99
|
+
for (const e of memEntries) {
|
|
100
|
+
if (e.isDirectory()) {
|
|
101
|
+
if (e.name === 'knowledge' || e.name === 'intake' || e.name === 'archive') continue;
|
|
102
|
+
const n = listFiles(path.join(memoryDir, e.name), ['.md', '.yml', '.yaml']).length;
|
|
103
|
+
counts.set(`memory/${e.name}`, n);
|
|
104
|
+
} else if (e.isFile() && (e.name.endsWith('.yml') || e.name.endsWith('.yaml'))) {
|
|
105
|
+
counts.set(`memory/${e.name}`, 1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return counts;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function runChecks(root: string): Warning[] {
|
|
112
|
+
const warnings: Warning[] = [];
|
|
113
|
+
|
|
114
|
+
// 1. Intake scale.
|
|
115
|
+
const intakeDir = path.join(root, 'agents', 'knowledge', 'intake');
|
|
116
|
+
const intakeFiles = listFiles(intakeDir, ['.jsonl']).filter((f) =>
|
|
117
|
+
path.basename(f).startsWith('events-'),
|
|
118
|
+
);
|
|
119
|
+
const intakeEvents = intakeFiles.reduce((acc, f) => acc + countJsonlLines(f), 0);
|
|
120
|
+
if (intakeEvents > INTAKE_EVENTS_MAX) {
|
|
121
|
+
warnings.push({
|
|
122
|
+
rule: 'intake-scale',
|
|
123
|
+
metric: `${intakeEvents}/${INTAKE_EVENTS_MAX}`,
|
|
124
|
+
message:
|
|
125
|
+
`intake holds ${intakeEvents} events (> ${INTAKE_EVENTS_MAX}). ` +
|
|
126
|
+
'Activation path (pre-decided): wire `src/scripts/fold_intake.ts` into the post-session/CI cadence.',
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 2. Sessions scale.
|
|
131
|
+
const sessionsDir = path.join(root, 'agents', 'knowledge', 'sessions');
|
|
132
|
+
const sessionPages = listFiles(sessionsDir, ['.md']).length;
|
|
133
|
+
if (sessionPages > SESSIONS_PAGES_MAX) {
|
|
134
|
+
warnings.push({
|
|
135
|
+
rule: 'sessions-scale',
|
|
136
|
+
metric: `${sessionPages}/${SESSIONS_PAGES_MAX}`,
|
|
137
|
+
message:
|
|
138
|
+
`agents/knowledge/sessions/ holds ${sessionPages} pages (> ${SESSIONS_PAGES_MAX}). ` +
|
|
139
|
+
'Activation path (pre-decided): design fold-through-consolidate-gate for tracked pages — never fold tracked files without the gate.',
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 3 + 4. Type + corpus scale.
|
|
144
|
+
const typeCounts = collectTypeCounts(root);
|
|
145
|
+
let total = 0;
|
|
146
|
+
for (const [type, n] of typeCounts) {
|
|
147
|
+
total += n;
|
|
148
|
+
if (n > TYPE_FILES_MAX) {
|
|
149
|
+
warnings.push({
|
|
150
|
+
rule: 'type-scale',
|
|
151
|
+
metric: `${n}/${TYPE_FILES_MAX}`,
|
|
152
|
+
message:
|
|
153
|
+
`type '${type}' holds ${n} files (> ${TYPE_FILES_MAX}). ` +
|
|
154
|
+
'Activation path (pre-decided): build the file-first in-memory BM25 CLI (re-index at session start, no vectors, no service).',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (total > CORPUS_FILES_MAX) {
|
|
159
|
+
warnings.push({
|
|
160
|
+
rule: 'corpus-scale',
|
|
161
|
+
metric: `${total}/${CORPUS_FILES_MAX}`,
|
|
162
|
+
message:
|
|
163
|
+
`memory/knowledge corpus holds ${total} files (> ${CORPUS_FILES_MAX}). ` +
|
|
164
|
+
'Activation path (pre-decided): build the file-first in-memory BM25 CLI (re-index at session start, no vectors, no service).',
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 5. Hot-context budget.
|
|
169
|
+
const hotContext = path.join(root, 'agents', 'runtime', 'state', 'hot-context.md');
|
|
170
|
+
let hotText = '';
|
|
171
|
+
try {
|
|
172
|
+
hotText = fs.readFileSync(hotContext, 'utf-8');
|
|
173
|
+
} catch {
|
|
174
|
+
// absent — fine (feature not active or fresh session)
|
|
175
|
+
}
|
|
176
|
+
if (hotText) {
|
|
177
|
+
const tokens = Math.ceil(hotText.length / CHARS_PER_TOKEN);
|
|
178
|
+
if (tokens > HOT_CONTEXT_TOKENS_MAX) {
|
|
179
|
+
warnings.push({
|
|
180
|
+
rule: 'hot-context-budget',
|
|
181
|
+
metric: `${tokens}/${HOT_CONTEXT_TOKENS_MAX}`,
|
|
182
|
+
message:
|
|
183
|
+
`hot-context.md parses to ~${tokens} tokens (> ${HOT_CONTEXT_TOKENS_MAX}). ` +
|
|
184
|
+
'Activation path (pre-decided): trim the schema sections or fix the deterministic writer cap.',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return warnings;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function main(argv: string[]): number {
|
|
193
|
+
let dir = '.';
|
|
194
|
+
let format = 'text';
|
|
195
|
+
let quiet = false;
|
|
196
|
+
for (let i = 0; i < argv.length; i++) {
|
|
197
|
+
const a = argv[i];
|
|
198
|
+
if (a === '--dir') {
|
|
199
|
+
dir = argv[++i] ?? '';
|
|
200
|
+
if (!dir) {
|
|
201
|
+
process.stderr.write(`${PROG}: error: --dir requires a value\n`);
|
|
202
|
+
return 1;
|
|
203
|
+
}
|
|
204
|
+
} else if (a === '--format') {
|
|
205
|
+
format = argv[++i] ?? '';
|
|
206
|
+
if (format !== 'text' && format !== 'json') {
|
|
207
|
+
process.stderr.write(`${PROG}: error: --format must be text|json\n`);
|
|
208
|
+
return 1;
|
|
209
|
+
}
|
|
210
|
+
} else if (a === '--quiet') {
|
|
211
|
+
quiet = true;
|
|
212
|
+
} else if (a === '-h' || a === '--help') {
|
|
213
|
+
process.stdout.write(
|
|
214
|
+
`usage: ${PROG} [--dir <repo-root>] [--format text|json] [--quiet]\n`,
|
|
215
|
+
);
|
|
216
|
+
return 0;
|
|
217
|
+
} else {
|
|
218
|
+
process.stderr.write(`${PROG}: error: unknown argument ${a}\n`);
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let warnings: Warning[];
|
|
224
|
+
try {
|
|
225
|
+
warnings = runChecks(path.resolve(dir));
|
|
226
|
+
} catch (exc) {
|
|
227
|
+
process.stderr.write(`${PROG}: internal error: ${String(exc)}\n`);
|
|
228
|
+
return 3;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (format === 'json') {
|
|
232
|
+
process.stdout.write(JSON.stringify({ warnings }, null, 2) + '\n');
|
|
233
|
+
} else if (warnings.length === 0) {
|
|
234
|
+
if (!quiet) {
|
|
235
|
+
process.stdout.write(`${PROG}: all scale tripwires silent (warn-only)\n`);
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
for (const w of warnings) {
|
|
239
|
+
process.stdout.write(`⚠️ [${w.rule}] ${w.metric} — ${w.message}\n`);
|
|
240
|
+
}
|
|
241
|
+
process.stdout.write(
|
|
242
|
+
`${PROG}: ${warnings.length} tripwire(s) fired — warn-only, build not failed\n`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
return 0;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (fileURLToPath(import.meta.url) === path.resolve(process.argv[1] ?? '')) {
|
|
249
|
+
process.exit(main(process.argv.slice(2)));
|
|
250
|
+
}
|
|
@@ -74,6 +74,62 @@ export function legalPromotionViolations(packsYml: string, legalNotice: string):
|
|
|
74
74
|
return [];
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
// D7 — reference-resolution gate for the floor rule itself. The
|
|
78
|
+
// `legal-safety-floor` rule is authored in `src/rules/` but SHIPS/PROJECTS to
|
|
79
|
+
// `dist/agent-src/rules/`; its relative links must resolve from that SHIPPED
|
|
80
|
+
// projection root (7.5.0 shipped a `LEGAL_NOTICE.md` path that only resolved
|
|
81
|
+
// from the projection — correct by design, but nothing asserted it, so a wrong
|
|
82
|
+
// depth could silently regress). `check_references` does not catch this: it
|
|
83
|
+
// only scans `dist/agent-src/` + `agents/` (never `src/`), and its PATH_PATTERN
|
|
84
|
+
// matches only directory-rooted paths (`skills/…`, `docs/…`), so a bare
|
|
85
|
+
// `../../../LEGAL_NOTICE.md` filename link is invisible to it. This gate is the
|
|
86
|
+
// complementary backstop — every markdown link target in the floor rule must
|
|
87
|
+
// resolve from the projected `dist/agent-src/rules/` location.
|
|
88
|
+
const PROJECTED_FLOOR_DIR = path.join(REPO, 'dist', 'agent-src', 'rules');
|
|
89
|
+
// Markdown inline link: [text](target). Captures the target.
|
|
90
|
+
const MD_LINK_RE = /\[[^\]]*\]\(([^)]+)\)/g;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Pure reference-resolution check for the floor rule. `ruleText` is the floor
|
|
94
|
+
* rule body (read from `src/rules/legal-safety-floor.md`); every relative
|
|
95
|
+
* markdown link target it contains MUST resolve from `projectedDir` (the
|
|
96
|
+
* shipped `dist/agent-src/rules/` location). External (http/anchor/mailto) and
|
|
97
|
+
* absolute targets are skipped. Returns a Violation per unresolvable link.
|
|
98
|
+
*/
|
|
99
|
+
export function legalFloorReferenceViolations(
|
|
100
|
+
ruleText: string,
|
|
101
|
+
projectedDir: string,
|
|
102
|
+
floorRel: string,
|
|
103
|
+
): Violation[] {
|
|
104
|
+
const out: Violation[] = [];
|
|
105
|
+
const seen = new Set<string>();
|
|
106
|
+
MD_LINK_RE.lastIndex = 0;
|
|
107
|
+
let m: RegExpExecArray | null;
|
|
108
|
+
while ((m = MD_LINK_RE.exec(ruleText)) !== null) {
|
|
109
|
+
let target = (m[1] ?? '').trim();
|
|
110
|
+
// Strip a fragment/anchor and any title (`path "Title"`).
|
|
111
|
+
const titleSplit = target.match(/^(\S+)\s+["'(]/);
|
|
112
|
+
if (titleSplit) target = titleSplit[1] ?? target;
|
|
113
|
+
const hashIdx = target.indexOf('#');
|
|
114
|
+
if (hashIdx >= 0) target = target.slice(0, hashIdx);
|
|
115
|
+
if (!target) continue;
|
|
116
|
+
// Skip non-path targets: external URLs, mailto, in-page anchors,
|
|
117
|
+
// absolute paths (resolution root is the projection, not the FS root).
|
|
118
|
+
if (/^([a-z][a-z0-9+.-]*:|#|\/)/i.test(target)) continue;
|
|
119
|
+
if (seen.has(target)) continue;
|
|
120
|
+
seen.add(target);
|
|
121
|
+
const resolved = path.resolve(projectedDir, target);
|
|
122
|
+
if (!fs.existsSync(resolved)) {
|
|
123
|
+
out.push({
|
|
124
|
+
file: floorRel,
|
|
125
|
+
rule: 'floor-reference',
|
|
126
|
+
msg: `link target "${target}" does not resolve from the shipped projection (dist/agent-src/rules/) — fix the relative depth so it resolves from the projected rule location`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
|
|
77
133
|
// D4 — definitive-legal-language blocklist (the floor bans these; this is the
|
|
78
134
|
// deterministic backstop over skill bodies). Narrow on purpose; the floor's
|
|
79
135
|
// prompt layer is the primary enforcement.
|
|
@@ -175,6 +231,17 @@ export function lintLegalPack(skillsDir: string = SKILLS_DIR): Violation[] {
|
|
|
175
231
|
if (fs.existsSync(PACKS_YML) && fs.existsSync(PACK_NOTICE)) {
|
|
176
232
|
violations.push(...legalPromotionViolations(_readText(PACKS_YML), _readText(PACK_NOTICE)));
|
|
177
233
|
}
|
|
234
|
+
// D7 — floor-rule reference gate: every link in the floor rule must
|
|
235
|
+
// resolve from its SHIPPED projection (dist/agent-src/rules/).
|
|
236
|
+
if (fs.existsSync(PROJECTED_FLOOR_DIR)) {
|
|
237
|
+
violations.push(
|
|
238
|
+
...legalFloorReferenceViolations(
|
|
239
|
+
_readText(FLOOR_RULE),
|
|
240
|
+
PROJECTED_FLOOR_DIR,
|
|
241
|
+
path.relative(REPO, FLOOR_RULE),
|
|
242
|
+
),
|
|
243
|
+
);
|
|
244
|
+
}
|
|
178
245
|
}
|
|
179
246
|
return violations;
|
|
180
247
|
}
|
|
@@ -26,10 +26,13 @@ const QUIET = process.argv.includes('--quiet');
|
|
|
26
26
|
|
|
27
27
|
const _HERE = fileURLToPath(import.meta.url);
|
|
28
28
|
const REPO = path.resolve(path.dirname(_HERE), '..', '..');
|
|
29
|
-
|
|
29
|
+
// Source of truth is `src/` (ADR-051); the old condensed-legacy source tree is
|
|
30
|
+
// empty post-py2ts, so the previous path silently scanned zero personas and the
|
|
31
|
+
// governance gate was inert. Scan the real source tree.
|
|
32
|
+
const PERSONA_DIR = path.join(REPO, 'src', 'agent-src', 'personas');
|
|
30
33
|
const SKILL_ROOTS: readonly string[] = [
|
|
31
|
-
path.join(REPO, '
|
|
32
|
-
path.join(REPO, '
|
|
34
|
+
path.join(REPO, 'src', 'skills'),
|
|
35
|
+
path.join(REPO, 'src', 'rules'),
|
|
33
36
|
];
|
|
34
37
|
|
|
35
38
|
// Per-domain cap — mirrors persona-governance.md § Per-domain cap.
|
|
@@ -38,6 +41,8 @@ const DOMAIN_MAP: Record<string, string> = {
|
|
|
38
41
|
'ai-video-technical-director': 'ai-video',
|
|
39
42
|
'backend-architect': 'backend',
|
|
40
43
|
'eloquent-tamer': 'backend',
|
|
44
|
+
'performance-engineer': 'performance',
|
|
45
|
+
'data-integrity': 'data',
|
|
41
46
|
cmo: 'gtm',
|
|
42
47
|
revops: 'gtm',
|
|
43
48
|
'growth-pm': 'growth',
|
|
@@ -114,6 +114,21 @@ function run_linter_json(ref: string | null, repo_root: string): LinterJson {
|
|
|
114
114
|
return { results: [], summary: {} };
|
|
115
115
|
}
|
|
116
116
|
const baselineArgs = ['--all', '--format', 'json', '--repo-root', tmpdir];
|
|
117
|
+
// Local python-skip guard (teardown D2): a historical `.py` baseline
|
|
118
|
+
// genuinely needs python3; when the runtime is absent, degrade to an
|
|
119
|
+
// empty baseline (same contract as a missing linter) instead of a
|
|
120
|
+
// spawn error — decouples the python-free-env shim retirement from
|
|
121
|
+
// porting pre-migration baselines to a frozen TS golden.
|
|
122
|
+
if (
|
|
123
|
+
baseline_linter.endsWith('.py') &&
|
|
124
|
+
spawnSync('python3', ['--version'], { encoding: 'utf8' }).status !== 0
|
|
125
|
+
) {
|
|
126
|
+
process.stderr.write(
|
|
127
|
+
`Warning: baseline '${ref}' is pre-migration (.py) and python3 is ` +
|
|
128
|
+
`unavailable — baseline treated as empty.\n`,
|
|
129
|
+
);
|
|
130
|
+
return { results: [], summary: {} };
|
|
131
|
+
}
|
|
117
132
|
const result = baseline_linter.endsWith('.ts')
|
|
118
133
|
? (() => {
|
|
119
134
|
const inv = _resolve_tsx_invocation(baseline_linter, baselineArgs);
|