@event4u/agent-config 7.5.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 +8 -1
- package/AGENTS.md +9 -9
- package/CHANGELOG.md +325 -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/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 +2 -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 +3 -5
- 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 +3 -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 +3 -5
- 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 +3 -5
- 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 +48 -42
- 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/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 +3 -3
- 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 +1 -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-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 +5 -2
- package/dist/agent-src/skills/design-intelligence/references/design-languages.md +1 -1
- package/dist/agent-src/skills/design-tokens/SKILL.md +10 -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/fe-design/SKILL.md +20 -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/judge-code-quality/SKILL.md +1 -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/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/reasoning-orchestrator/SKILL.md +3 -1
- package/dist/agent-src/skills/release-comms/SKILL.md +46 -45
- package/dist/agent-src/skills/roadmap-management/SKILL.md +21 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +32 -2
- package/dist/agent-src/skills/root-cause-frameworks/SKILL.md +0 -3
- 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/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 +29 -0
- package/dist/agent-src/skills/threat-modeling/SKILL.md +2 -2
- package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
- 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 +718 -240
- 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 +43 -28
- package/dist/discovery/trust-report.md +12 -11
- package/dist/discovery/workspaces.json +29 -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 +3 -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 +5 -5
- package/docs/benchmark.md +133 -2
- package/docs/benchmark.pinned.yml +31 -0
- package/docs/capability-matrix.md +1 -0
- package/docs/catalog.md +70 -60
- package/docs/command-flows.md +15 -3
- 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 +10 -1
- 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 +59 -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 +15 -0
- package/src/scripts/design_slop_rules.ts +28 -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 +7 -2
- 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 +26 -14
- 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_agents_layout.ts +74 -15
- package/src/scripts/lint_bench_ab.ts +4 -1
- 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,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);
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Hard-gate linter for the roadmap `## Blockers` contract
|
|
4
|
+
* (`templates/roadmaps.md` rule 20 / `roadmap-ci-steps-policy` siblings).
|
|
5
|
+
*
|
|
6
|
+
* Validates, for every active roadmap under `agents/roadmaps/*.md`:
|
|
7
|
+
*
|
|
8
|
+
* 1. Every `### blocker: <id>` entry declares all five required fields
|
|
9
|
+
* (Status, Owner, Blocks, What to do, Resolved when).
|
|
10
|
+
* 2. Every inline `<!-- blocked-by: <id> -->` annotation resolves to a
|
|
11
|
+
* `### blocker: <id>` entry declared in the SAME file.
|
|
12
|
+
*
|
|
13
|
+
* Fenced code blocks are stripped before scanning so a roadmap that shows
|
|
14
|
+
* the `## Blockers` shape as a documentation example is not flagged.
|
|
15
|
+
*
|
|
16
|
+
* Exit codes: 0 = clean / no active roadmaps, 1 = violations.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import * as fs from 'node:fs';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
22
|
+
|
|
23
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
24
|
+
const QUIET = process.argv.slice(2).includes('--quiet');
|
|
25
|
+
|
|
26
|
+
const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
27
|
+
const ROADMAP_GLOB = 'agents/roadmaps/*.md';
|
|
28
|
+
|
|
29
|
+
const FENCED_CODE_RE = /^[ \t]*```[^\n]*\n[\s\S]*?^[ \t]*```[ \t]*$/gm;
|
|
30
|
+
const BLOCKERS_SECTION_RE = /^##[ \t]+Blockers[ \t]*$/im;
|
|
31
|
+
const NEXT_H2_RE = /^##[ \t]+\S/m;
|
|
32
|
+
const BLOCKER_HEADING_RE = /^###[ \t]+blocker:[ \t]*(.+?)[ \t]*$/gim;
|
|
33
|
+
// Only a real checkbox line (`- [ ] … <!-- blocked-by: id -->`) counts — a
|
|
34
|
+
// wrapped continuation line or inline-code documentation example of the
|
|
35
|
+
// syntax (as this very lint script's own roadmap step describes it) must
|
|
36
|
+
// not be mistaken for a live cross-reference.
|
|
37
|
+
const BLOCKED_BY_LINE_RE = /^-[ \t]*\[[ xX~-]\].*<!--[ \t]*blocked-by:[ \t]*([a-z0-9-]+)[ \t]*-->/i;
|
|
38
|
+
|
|
39
|
+
const REQUIRED_FIELDS: ReadonlyArray<readonly [string, RegExp]> = [
|
|
40
|
+
['Status', /^-[ \t]*\*\*Status:\*\*/im],
|
|
41
|
+
['Owner', /^-[ \t]*\*\*Owner:\*\*/im],
|
|
42
|
+
['Blocks', /^-[ \t]*\*\*Blocks:\*\*/im],
|
|
43
|
+
['What to do', /^-[ \t]*\*\*What to do:\*\*/im],
|
|
44
|
+
['Resolved when', /^-[ \t]*\*\*Resolved when:\*\*/im],
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
interface Violation {
|
|
48
|
+
line: number;
|
|
49
|
+
message: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** 1-based line number of a character offset. */
|
|
53
|
+
function _lineAt(text: string, index: number): number {
|
|
54
|
+
let n = 1;
|
|
55
|
+
for (let i = 0; i < index && i < text.length; i++) {
|
|
56
|
+
if (text.charCodeAt(i) === 10) {
|
|
57
|
+
n += 1;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return n;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Blank out fenced code blocks, preserving line count and offsets. */
|
|
64
|
+
function _stripFencedCode(text: string): string {
|
|
65
|
+
return text.replace(FENCED_CODE_RE, (m) => '\n'.repeat((m.match(/\n/g) ?? []).length));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function _scan(rawText: string): Violation[] {
|
|
69
|
+
const violations: Violation[] = [];
|
|
70
|
+
const text = _stripFencedCode(rawText);
|
|
71
|
+
const declaredIds = new Set<string>();
|
|
72
|
+
|
|
73
|
+
const sectionMatch = BLOCKERS_SECTION_RE.exec(text);
|
|
74
|
+
if (sectionMatch) {
|
|
75
|
+
const sectionStart = sectionMatch.index + sectionMatch[0].length;
|
|
76
|
+
const rest = text.slice(sectionStart);
|
|
77
|
+
const h2 = NEXT_H2_RE.exec(rest);
|
|
78
|
+
const sectionEnd = h2 ? sectionStart + h2.index : text.length;
|
|
79
|
+
const section = text.slice(sectionStart, sectionEnd);
|
|
80
|
+
|
|
81
|
+
BLOCKER_HEADING_RE.lastIndex = 0;
|
|
82
|
+
const heads: Array<{ start: number; end: number; id: string }> = [];
|
|
83
|
+
let hm: RegExpExecArray | null;
|
|
84
|
+
while ((hm = BLOCKER_HEADING_RE.exec(section)) !== null) {
|
|
85
|
+
heads.push({
|
|
86
|
+
start: hm.index,
|
|
87
|
+
end: hm.index + hm[0].length,
|
|
88
|
+
id: (hm[1] as string).trim(),
|
|
89
|
+
});
|
|
90
|
+
if (hm.index === BLOCKER_HEADING_RE.lastIndex) {
|
|
91
|
+
BLOCKER_HEADING_RE.lastIndex++;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (let i = 0; i < heads.length; i++) {
|
|
95
|
+
const cur = heads[i] as { start: number; end: number; id: string };
|
|
96
|
+
declaredIds.add(cur.id);
|
|
97
|
+
const bodyEnd = i + 1 < heads.length ? (heads[i + 1] as { start: number }).start : section.length;
|
|
98
|
+
const body = section.slice(cur.end, bodyEnd);
|
|
99
|
+
const missing = REQUIRED_FIELDS.filter(([, re]) => !re.test(body)).map(([name]) => name);
|
|
100
|
+
if (missing.length) {
|
|
101
|
+
violations.push({
|
|
102
|
+
line: _lineAt(text, sectionStart + cur.start),
|
|
103
|
+
message: `blocker '${cur.id}' missing required field(s): ${missing.join(', ')}`,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const lines = text.split('\n');
|
|
110
|
+
for (let i = 0; i < lines.length; i++) {
|
|
111
|
+
// A real annotation is bare markdown (an actual checkbox + HTML
|
|
112
|
+
// comment); an inline-code-quoted mention (`` `<!-- blocked-by: id -->` ``,
|
|
113
|
+
// e.g. this very lint script's own roadmap step documenting the
|
|
114
|
+
// syntax) is prose, not a live cross-reference — blank inline code
|
|
115
|
+
// spans before matching.
|
|
116
|
+
const cleaned = (lines[i] as string).replace(/`[^`\n]*`/g, (m) => ' '.repeat(m.length));
|
|
117
|
+
const m = BLOCKED_BY_LINE_RE.exec(cleaned);
|
|
118
|
+
if (!m) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const id = m[1] as string;
|
|
122
|
+
if (!declaredIds.has(id)) {
|
|
123
|
+
violations.push({
|
|
124
|
+
line: i + 1,
|
|
125
|
+
message:
|
|
126
|
+
`blocked-by references unknown blocker id '${id}' ` +
|
|
127
|
+
`(no matching '### blocker: ${id}' in this file)`,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
violations.sort((a, b) => a.line - b.line);
|
|
132
|
+
return violations;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Sorted `agents/roadmaps/*.md` (non-recursive — active roadmaps only). */
|
|
136
|
+
function _globRoadmaps(): string[] {
|
|
137
|
+
const dir = path.join(REPO_ROOT, 'agents', 'roadmaps');
|
|
138
|
+
let entries: fs.Dirent[];
|
|
139
|
+
try {
|
|
140
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
141
|
+
} catch {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const out: string[] = [];
|
|
145
|
+
for (const entry of entries) {
|
|
146
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
147
|
+
out.push(path.join(dir, entry.name));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return out.sort();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _relPosix(target: string, root: string): string {
|
|
154
|
+
return path.relative(root, target).split(path.sep).join('/');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function main(): number {
|
|
158
|
+
const roadmaps = _globRoadmaps();
|
|
159
|
+
if (roadmaps.length === 0) {
|
|
160
|
+
if (!QUIET) {
|
|
161
|
+
process.stdout.write(`✅ no active roadmaps under ${ROADMAP_GLOB}\n`);
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
let failed = 0;
|
|
166
|
+
for (const roadmap of roadmaps) {
|
|
167
|
+
const rel = _relPosix(roadmap, REPO_ROOT);
|
|
168
|
+
const text = fs.readFileSync(roadmap, 'utf-8');
|
|
169
|
+
const violations = _scan(text);
|
|
170
|
+
if (violations.length) {
|
|
171
|
+
failed += 1;
|
|
172
|
+
process.stderr.write(`❌ ${rel}\n`);
|
|
173
|
+
for (const v of violations) {
|
|
174
|
+
process.stderr.write(` line ${v.line}: ${v.message}\n`);
|
|
175
|
+
}
|
|
176
|
+
} else if (!QUIET) {
|
|
177
|
+
process.stdout.write(`✅ ${rel}\n`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (failed) {
|
|
181
|
+
process.stderr.write(
|
|
182
|
+
`\n❌ ${failed} roadmap(s) violate the ## Blockers contract — ` +
|
|
183
|
+
'see .augment/rules/roadmap-progress-sync.md and ' +
|
|
184
|
+
'.augment/templates/roadmaps.md rule 20\n',
|
|
185
|
+
);
|
|
186
|
+
return 1;
|
|
187
|
+
}
|
|
188
|
+
if (!QUIET) {
|
|
189
|
+
process.stdout.write(`\n✅ ${roadmaps.length} roadmap(s) blocker-contract-clean\n`);
|
|
190
|
+
}
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const _isCliEntry =
|
|
195
|
+
process.argv[1] !== undefined &&
|
|
196
|
+
import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href;
|
|
197
|
+
if (_isCliEntry || process.argv[1] === _HERE) {
|
|
198
|
+
process.exit(main());
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export { REPO_ROOT, ROADMAP_GLOB, REQUIRED_FIELDS, _scan, _globRoadmaps, main };
|
|
202
|
+
export type { Violation };
|