@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,258 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Janitor — retention sweep for volatile/TTL directories.
|
|
4
|
+
*
|
|
5
|
+
* Supported TTL directories (per docs/contracts/agents-layout.md):
|
|
6
|
+
* agents/tmp.old/ — processed inbox archive (TTL: 30 days)
|
|
7
|
+
* agents/runtime/ — volatile runtime artefacts (TTL: 7 days for council/tmp)
|
|
8
|
+
*
|
|
9
|
+
* NEVER auto-sweeps agents/tmp/ (user inbox — user-owned, no TTL).
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ./scripts-run src/scripts/janitor — dry-run report only
|
|
13
|
+
* ./scripts-run src/scripts/janitor --apply — delete expired files
|
|
14
|
+
* ./scripts-run src/scripts/janitor --report — same as default (dry-run)
|
|
15
|
+
*
|
|
16
|
+
* Exit codes:
|
|
17
|
+
* 0 — report generated (dry-run) or sweep completed (--apply)
|
|
18
|
+
* 2 — invalid args
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
25
|
+
const REPO_ROOT = path.join(path.dirname(_HERE), '..', '..');
|
|
26
|
+
|
|
27
|
+
// TTL configuration per directory (days)
|
|
28
|
+
const TTL_CONFIG: ReadonlyArray<{ dir: string; ttlDays: number; description: string }> = [
|
|
29
|
+
{
|
|
30
|
+
dir: 'agents/tmp.old',
|
|
31
|
+
ttlDays: 30,
|
|
32
|
+
description: 'Processed inbox archive (consumed agents/tmp/ files)',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
dir: 'agents/runtime/tmp',
|
|
36
|
+
ttlDays: 7,
|
|
37
|
+
description: 'Agent scratch / runtime tmp',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
dir: 'agents/runtime/council/responses',
|
|
41
|
+
ttlDays: 7,
|
|
42
|
+
description: 'Council response cache',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
// Directories that must NEVER be auto-swept
|
|
47
|
+
const PROTECTED_DIRS: ReadonlySet<string> = new Set([
|
|
48
|
+
'agents/tmp', // user inbox — user-owned, no TTL
|
|
49
|
+
'agents/knowledge', // committed curated pages
|
|
50
|
+
'agents/memory', // promotion pipeline (committed YAML)
|
|
51
|
+
'agents/decisions', // permanent durable records
|
|
52
|
+
'agents/evidence', // permanent durable evidence
|
|
53
|
+
'agents/roadmaps', // tracked roadmaps
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
interface FileStat {
|
|
57
|
+
relPath: string;
|
|
58
|
+
absPath: string;
|
|
59
|
+
ageDays: number;
|
|
60
|
+
size: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function _isDir(p: string): boolean {
|
|
64
|
+
try {
|
|
65
|
+
return fs.statSync(p).isDirectory();
|
|
66
|
+
} catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function _walkFiles(dir: string): string[] {
|
|
72
|
+
const results: string[] = [];
|
|
73
|
+
if (!_isDir(dir)) return results;
|
|
74
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
75
|
+
const full = path.join(dir, entry);
|
|
76
|
+
const stat = fs.statSync(full);
|
|
77
|
+
if (stat.isFile()) {
|
|
78
|
+
results.push(full);
|
|
79
|
+
} else if (stat.isDirectory()) {
|
|
80
|
+
results.push(..._walkFiles(full));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _ageDays(p: string): number {
|
|
87
|
+
try {
|
|
88
|
+
const stat = fs.statSync(p);
|
|
89
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
90
|
+
return ageMs / (1000 * 60 * 60 * 24);
|
|
91
|
+
} catch {
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function _humanSize(bytes: number): string {
|
|
97
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
98
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}kB`;
|
|
99
|
+
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function report(apply: boolean): void {
|
|
103
|
+
const now = new Date();
|
|
104
|
+
process.stdout.write(`\n🗂️ Janitor report — ${now.toISOString().slice(0, 10)}\n\n`);
|
|
105
|
+
|
|
106
|
+
// Inbox status (never swept, report only)
|
|
107
|
+
const inboxDir = path.join(REPO_ROOT, 'agents/tmp');
|
|
108
|
+
if (_isDir(inboxDir)) {
|
|
109
|
+
const files = _walkFiles(inboxDir);
|
|
110
|
+
if (files.length === 0) {
|
|
111
|
+
process.stdout.write(`✅ agents/tmp/ (user inbox) — empty\n`);
|
|
112
|
+
} else {
|
|
113
|
+
const oldest = files.map((f) => _ageDays(f)).reduce((a, b) => Math.max(a, b), 0);
|
|
114
|
+
const totalSize = files.reduce((s, f) => {
|
|
115
|
+
try { return s + fs.statSync(f).size; } catch { return s; }
|
|
116
|
+
}, 0);
|
|
117
|
+
process.stdout.write(
|
|
118
|
+
`📥 agents/tmp/ (user inbox) — ${files.length} file(s), ` +
|
|
119
|
+
`oldest: ${oldest.toFixed(0)}d, size: ${_humanSize(totalSize)}\n` +
|
|
120
|
+
` (user-owned; never auto-swept)\n`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
process.stdout.write('\n');
|
|
126
|
+
|
|
127
|
+
// Harvest-local size note
|
|
128
|
+
const harvestDir = path.join(REPO_ROOT, 'agents/.harvest-local');
|
|
129
|
+
if (_isDir(harvestDir)) {
|
|
130
|
+
const files = _walkFiles(harvestDir);
|
|
131
|
+
const totalSize = files.reduce((s, f) => {
|
|
132
|
+
try { return s + fs.statSync(f).size; } catch { return s; }
|
|
133
|
+
}, 0);
|
|
134
|
+
process.stdout.write(
|
|
135
|
+
`📦 agents/.harvest-local/ — ${_humanSize(totalSize)} ` +
|
|
136
|
+
`(source-confidentiality evidence; retain, never auto-deleted)\n\n`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let totalExpired = 0;
|
|
141
|
+
let totalSize = 0;
|
|
142
|
+
|
|
143
|
+
for (const { dir, ttlDays, description } of TTL_CONFIG) {
|
|
144
|
+
const absDir = path.join(REPO_ROOT, dir);
|
|
145
|
+
if (!_isDir(absDir)) continue;
|
|
146
|
+
|
|
147
|
+
// Safety: never sweep protected dirs
|
|
148
|
+
if (PROTECTED_DIRS.has(dir)) {
|
|
149
|
+
process.stdout.write(`🔒 ${dir} — protected, skipping\n`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const files = _walkFiles(absDir);
|
|
154
|
+
const expired: FileStat[] = [];
|
|
155
|
+
|
|
156
|
+
for (const absPath of files) {
|
|
157
|
+
const ageDays = _ageDays(absPath);
|
|
158
|
+
if (ageDays >= ttlDays) {
|
|
159
|
+
let size = 0;
|
|
160
|
+
try { size = fs.statSync(absPath).size; } catch { /* */ }
|
|
161
|
+
expired.push({ relPath: path.relative(REPO_ROOT, absPath), absPath, ageDays, size });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (files.length === 0) {
|
|
166
|
+
process.stdout.write(`✅ ${dir}/ — empty\n`);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const dirSize = files.reduce((s, f) => {
|
|
171
|
+
try { return s + fs.statSync(f).size; } catch { return s; }
|
|
172
|
+
}, 0);
|
|
173
|
+
process.stdout.write(
|
|
174
|
+
`📁 ${dir}/ — ${files.length} file(s), ${_humanSize(dirSize)} total, ` +
|
|
175
|
+
`TTL: ${ttlDays}d (${description})\n`,
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
if (expired.length === 0) {
|
|
179
|
+
process.stdout.write(` ✅ No expired files.\n`);
|
|
180
|
+
} else {
|
|
181
|
+
const expiredSize = expired.reduce((s, f) => s + f.size, 0);
|
|
182
|
+
process.stdout.write(
|
|
183
|
+
` ⚠️ ${expired.length} expired file(s), ${_humanSize(expiredSize)} reclaimable:\n`,
|
|
184
|
+
);
|
|
185
|
+
for (const f of expired.slice(0, 10)) {
|
|
186
|
+
process.stdout.write(
|
|
187
|
+
` ${f.relPath} (${f.ageDays.toFixed(0)}d old, ${_humanSize(f.size)})\n`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
if (expired.length > 10) {
|
|
191
|
+
process.stdout.write(` … and ${expired.length - 10} more\n`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (apply) {
|
|
195
|
+
for (const f of expired) {
|
|
196
|
+
try { fs.unlinkSync(f.absPath); } catch { /* ignore */ }
|
|
197
|
+
}
|
|
198
|
+
// Remove empty dirs
|
|
199
|
+
for (const f of expired) {
|
|
200
|
+
let dir = path.dirname(f.absPath);
|
|
201
|
+
while (dir.startsWith(absDir) && dir !== absDir) {
|
|
202
|
+
try {
|
|
203
|
+
if (fs.readdirSync(dir).length === 0) {
|
|
204
|
+
fs.rmdirSync(dir);
|
|
205
|
+
}
|
|
206
|
+
} catch { /* */ }
|
|
207
|
+
dir = path.dirname(dir);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
process.stdout.write(` 🗑️ Deleted ${expired.length} expired file(s).\n`);
|
|
211
|
+
} else {
|
|
212
|
+
process.stdout.write(
|
|
213
|
+
` → Run with --apply to delete. All files stay on disk in dry-run mode.\n`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
totalExpired += expired.length;
|
|
218
|
+
totalSize += expired.reduce((s, f) => s + f.size, 0);
|
|
219
|
+
}
|
|
220
|
+
process.stdout.write('\n');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!apply && totalExpired > 0) {
|
|
224
|
+
process.stdout.write(
|
|
225
|
+
`Total reclaimable: ${totalExpired} file(s), ${_humanSize(totalSize)}\n` +
|
|
226
|
+
`Run \`./scripts-run src/scripts/janitor --apply\` to delete.\n`,
|
|
227
|
+
);
|
|
228
|
+
} else if (apply && totalExpired > 0) {
|
|
229
|
+
process.stdout.write(`Total deleted: ${totalExpired} file(s), ${_humanSize(totalSize)} freed.\n`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function main(argv?: readonly string[]): number {
|
|
234
|
+
const args = argv ?? process.argv.slice(2);
|
|
235
|
+
|
|
236
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
237
|
+
process.stdout.write(
|
|
238
|
+
'Usage: janitor [--apply] [--report]\n' +
|
|
239
|
+
' (no flags) — dry-run report\n' +
|
|
240
|
+
' --report — same as no flags\n' +
|
|
241
|
+
' --apply — delete expired files\n',
|
|
242
|
+
);
|
|
243
|
+
return 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const apply = args.includes('--apply');
|
|
247
|
+
report(apply);
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const _isCliEntry =
|
|
252
|
+
process.argv[1] !== undefined &&
|
|
253
|
+
import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href;
|
|
254
|
+
if (_isCliEntry || process.argv[1] === _HERE) {
|
|
255
|
+
process.exit(main());
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export { main, TTL_CONFIG, PROTECTED_DIRS };
|
|
@@ -43,6 +43,7 @@ type Finding = Record<string, unknown>;
|
|
|
43
43
|
|
|
44
44
|
const LINTERS: ReadonlyArray<[string, string]> = [
|
|
45
45
|
["hidden-unicode", "lint_hidden_unicode.ts"],
|
|
46
|
+
["mixed-script-confusable", "lint_confusables.ts"],
|
|
46
47
|
["instruction-smuggling", "lint_instruction_smuggling.ts"],
|
|
47
48
|
["mcp-config-security", "lint_mcp_config_security.ts"],
|
|
48
49
|
["dangerous-frontmatter", "lint_skill_frontmatter_safety.ts"],
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
* uses the cwd-relative `agents/` root exactly as the Python does, so the
|
|
15
15
|
* printed paths (`agents/<name>`) match byte-for-byte.
|
|
16
16
|
*
|
|
17
|
-
*
|
|
17
|
+
* Extended (road-to-agents-dir-and-gitignore-hygiene Phase 2.3):
|
|
18
|
+
* - In source-repo mode, unknown TOP-LEVEL DIRECTORIES also become errors.
|
|
19
|
+
* Whitelist is ALLOWED_SOURCE_DIRS (see docs/contracts/agents-layout.md).
|
|
20
|
+
* - CONSUMER_EXPECTED_ENTRIES extended with the full consumer-scope subset
|
|
21
|
+
* from the contract (knowledge/, memory/, roadmaps/, tmp/, tmp.old/).
|
|
18
22
|
*/
|
|
19
23
|
|
|
20
24
|
import * as fs from 'node:fs';
|
|
@@ -33,12 +37,57 @@ const ALLOWED_FLAT_FILES: ReadonlySet<string> = new Set([
|
|
|
33
37
|
'.event4u-bridge.yml',
|
|
34
38
|
'.agent-tools.yml',
|
|
35
39
|
'.maintainer-workspace.md',
|
|
40
|
+
// Gitignored local-only files (present in working tree, never committed).
|
|
41
|
+
// NOTE: if any of these are tracked (appear in `git ls-files`), that is a
|
|
42
|
+
// separate violation caught by check_tracked_but_ignored.ts.
|
|
43
|
+
'.ai-video.xml', // operator AI-video config; gitignored per .gitignore § AI Video
|
|
44
|
+
'installed-tools.lock', // installer per-user inventory; gitignored per ADR-020
|
|
45
|
+
'.event4u-bridge.yml', // consumer bridge marker; ADR-020 (should only be in consumers)
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
// All directories allowed at the agents/ root in the SOURCE REPO.
|
|
49
|
+
// Entries marked (* consumer) are also allowed in consumer projects.
|
|
50
|
+
// Contract: docs/contracts/agents-layout.md § Directory table.
|
|
51
|
+
const ALLOWED_SOURCE_DIRS: ReadonlySet<string> = new Set([
|
|
52
|
+
'decisions',
|
|
53
|
+
'evidence',
|
|
54
|
+
'features',
|
|
55
|
+
'knowledge', // * consumer
|
|
56
|
+
'memory', // * consumer
|
|
57
|
+
'notes', // legacy; new files go to evidence/notes/
|
|
58
|
+
'reports', // legacy; new files go to evidence/reports/ (see agents-layout.md)
|
|
59
|
+
'overrides', // * consumer
|
|
60
|
+
'recruit-sessions',
|
|
61
|
+
'reference',
|
|
62
|
+
'roadmap-assets',
|
|
63
|
+
'roadmaps', // * consumer
|
|
64
|
+
'roles',
|
|
65
|
+
'runtime', // local-only, gitignored
|
|
66
|
+
'settings',
|
|
67
|
+
'state', // local-only, gitignored
|
|
68
|
+
'templates',
|
|
69
|
+
'tickets',
|
|
70
|
+
'tmp', // local-only, gitignored (* consumer)
|
|
71
|
+
'tmp.old', // local-only, gitignored (* consumer)
|
|
72
|
+
'.harvest-local', // local-only, gitignored
|
|
36
73
|
]);
|
|
37
74
|
|
|
38
75
|
const CONSUMER_EXPECTED_ENTRIES: ReadonlySet<string> = new Set([
|
|
76
|
+
// Required consumer entries
|
|
39
77
|
'overrides',
|
|
40
78
|
'.event4u-bridge.yml',
|
|
41
79
|
'.gitkeep',
|
|
80
|
+
// Optional but legitimate consumer entries (will not trigger warnings)
|
|
81
|
+
'knowledge',
|
|
82
|
+
'memory',
|
|
83
|
+
'roadmaps',
|
|
84
|
+
'tmp',
|
|
85
|
+
'tmp.old',
|
|
86
|
+
// Flat files that are tracked in consumers
|
|
87
|
+
'index.md',
|
|
88
|
+
'roadmaps-progress.md',
|
|
89
|
+
'.agent-tools.yml',
|
|
90
|
+
'.maintainer-workspace.md',
|
|
42
91
|
]);
|
|
43
92
|
|
|
44
93
|
const MIGRATE_HINT =
|
|
@@ -99,26 +148,35 @@ function is_source_repo(projectRoot: string): boolean {
|
|
|
99
148
|
return false;
|
|
100
149
|
}
|
|
101
150
|
|
|
102
|
-
function find_violations(root: string): string[] {
|
|
151
|
+
function find_violations(root: string, sourceRepo = false): string[] {
|
|
103
152
|
const unknown: string[] = [];
|
|
104
153
|
if (!_isDir(root)) {
|
|
105
154
|
return unknown;
|
|
106
155
|
}
|
|
107
156
|
for (const p of _iterdirSorted(root)) {
|
|
108
|
-
if (!_isFile(p)) {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
157
|
const name = path.basename(p);
|
|
112
|
-
if (
|
|
113
|
-
|
|
158
|
+
if (_isFile(p)) {
|
|
159
|
+
if (ALLOWED_FLAT_FILES.has(name)) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
unknown.push(
|
|
163
|
+
`${p}: flat file not in agents/ whitelist — move to a typed ` +
|
|
164
|
+
'subdirectory (runtime/, evidence/, decisions/, settings/, ' +
|
|
165
|
+
'audits/, roadmaps/, policies/, contexts/, …) or add to ' +
|
|
166
|
+
'ALLOWED_FLAT_FILES in scripts/lint_agents_layout.ts with ' +
|
|
167
|
+
'rationale.',
|
|
168
|
+
);
|
|
169
|
+
} else if (_isDir(p) && sourceRepo) {
|
|
170
|
+
// In source-repo mode, unknown top-level directories are also errors.
|
|
171
|
+
// See docs/contracts/agents-layout.md § Directory table.
|
|
172
|
+
if (!ALLOWED_SOURCE_DIRS.has(name)) {
|
|
173
|
+
unknown.push(
|
|
174
|
+
`${p}: unknown top-level directory in agents/ — ` +
|
|
175
|
+
'add to ALLOWED_SOURCE_DIRS in lint_agents_layout.ts ' +
|
|
176
|
+
'(with rationale) AND to docs/contracts/agents-layout.md.',
|
|
177
|
+
);
|
|
178
|
+
}
|
|
114
179
|
}
|
|
115
|
-
unknown.push(
|
|
116
|
-
`${p}: flat file not in agents/ whitelist — move to a typed ` +
|
|
117
|
-
'subdirectory (runtime/, evidence/, decisions/, settings/, ' +
|
|
118
|
-
'audits/, roadmaps/, policies/, contexts/, …) or add to ' +
|
|
119
|
-
'ALLOWED_FLAT_FILES in scripts/lint_agents_layout.py with ' +
|
|
120
|
-
'rationale.',
|
|
121
|
-
);
|
|
122
180
|
}
|
|
123
181
|
return unknown;
|
|
124
182
|
}
|
|
@@ -149,8 +207,8 @@ function main(argv?: readonly string[]): number {
|
|
|
149
207
|
const quiet = args.includes('--quiet');
|
|
150
208
|
|
|
151
209
|
const projectRoot = process.cwd();
|
|
152
|
-
const unknown = find_violations(AGENTS_ROOT);
|
|
153
210
|
const consumerMode = !is_source_repo(projectRoot);
|
|
211
|
+
const unknown = find_violations(AGENTS_ROOT, !consumerMode);
|
|
154
212
|
const warnings = consumerMode ? find_consumer_warnings(AGENTS_ROOT) : [];
|
|
155
213
|
|
|
156
214
|
if (unknown.length > 0) {
|
|
@@ -196,6 +254,7 @@ if (_isCliEntry || process.argv[1] === _HERE) {
|
|
|
196
254
|
export {
|
|
197
255
|
AGENTS_ROOT,
|
|
198
256
|
ALLOWED_FLAT_FILES,
|
|
257
|
+
ALLOWED_SOURCE_DIRS,
|
|
199
258
|
CONSUMER_EXPECTED_ENTRIES,
|
|
200
259
|
MIGRATE_HINT,
|
|
201
260
|
is_source_repo,
|
|
@@ -32,7 +32,10 @@ const REQUIRED_SECTIONS = [
|
|
|
32
32
|
// bench_ab_v2_stats.py --markdown). The v1 Headline/Track-A/Track-B/History
|
|
33
33
|
// structure was retired with the v1 binary-capability frame.
|
|
34
34
|
'## Honesty labels',
|
|
35
|
-
|
|
35
|
+
// Since the 2026-07 per-host split the verdict lives inside per-host h2
|
|
36
|
+
// headings ("## Weak host (…) — Gate verdict: **PASS**"), so match the
|
|
37
|
+
// verdict label rather than a standalone "## Gate verdict" section.
|
|
38
|
+
'Gate verdict:',
|
|
36
39
|
'## Methodology',
|
|
37
40
|
] as const;
|
|
38
41
|
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Visible mixed-script confusable / homoglyph linter
|
|
2
|
+
// (road-to-injection-defense-pressure-corpus.md, Phase 1.2).
|
|
3
|
+
//
|
|
4
|
+
// Sibling of `lint_hidden_unicode.ts`. That linter catches the INVISIBLE
|
|
5
|
+
// smuggling class (zero-width, bidi, tag-block). This one catches the VISIBLE
|
|
6
|
+
// class it misses: a Latin word with one or more letters swapped for
|
|
7
|
+
// visually-identical Cyrillic or Greek lookalikes (mixed-script token) — the
|
|
8
|
+
// homoglyph version of the rules-file-backdoor attack. A reviewer sees
|
|
9
|
+
// "ignore"; the model reads a token whose 'o' is U+043E CYRILLIC SMALL LETTER O.
|
|
10
|
+
//
|
|
11
|
+
// Detection signature (high-precision, low-false-positive):
|
|
12
|
+
// A whitespace-delimited token is flagged when ALL hold —
|
|
13
|
+
// 1. it contains >= 1 Latin letter AND >= 1 Cyrillic-or-Greek letter that
|
|
14
|
+
// is in the TR39 confusable set (has a Latin lookalike). Math operators
|
|
15
|
+
// with NO Latin lookalike (Δ Σ Π Ω Φ Θ Λ Ξ Ψ Γ …) are NOT confusables,
|
|
16
|
+
// so legit notation like "ΔNWC" / "Σwᵢ" is never flagged,
|
|
17
|
+
// 2. it has >= MIN_LETTERS total letters, and
|
|
18
|
+
// 3. Latin is the MAJORITY script (the attack is a Latin word with foreign
|
|
19
|
+
// lookalike substitutions, not a foreign word with one Latin letter).
|
|
20
|
+
// Pure-Cyrillic / pure-Greek / CJK prose is single-script per token and is
|
|
21
|
+
// never flagged — legit non-Latin text passes.
|
|
22
|
+
//
|
|
23
|
+
// Scope + containment mirror lint_hidden_unicode: scans every .md under
|
|
24
|
+
// src/{skills,rules,agent-src,domains} via sl.iter_corpus(); a
|
|
25
|
+
// ```security-example fence or a `security-lint: allow mixed-script-confusable`
|
|
26
|
+
// pragma exempts a region/file (a doc teaching confusables needs to show one).
|
|
27
|
+
//
|
|
28
|
+
// Exit 0 clean, 1 on any blocking finding.
|
|
29
|
+
//
|
|
30
|
+
// Usage: ./scripts-run src/scripts/lint_confusables [--json]
|
|
31
|
+
|
|
32
|
+
import * as path from 'node:path';
|
|
33
|
+
import { pathToFileURL } from 'node:url';
|
|
34
|
+
|
|
35
|
+
import * as sl from './_lib/security_lint.js';
|
|
36
|
+
|
|
37
|
+
export const CHECK = 'mixed-script-confusable';
|
|
38
|
+
|
|
39
|
+
const MIN_LETTERS = 3;
|
|
40
|
+
|
|
41
|
+
// Unicode-script classifiers via property escapes (requires the `u` flag).
|
|
42
|
+
const _LATIN = /\p{Script=Latin}/u;
|
|
43
|
+
const _CYRILLIC = /\p{Script=Cyrillic}/u;
|
|
44
|
+
const _GREEK = /\p{Script=Greek}/u;
|
|
45
|
+
const _LETTER = /\p{L}/u;
|
|
46
|
+
// A "token" is a maximal run of letters / combining marks / decimal digits.
|
|
47
|
+
const _TOKEN = /[\p{L}\p{M}\p{Nd}]+/gu;
|
|
48
|
+
|
|
49
|
+
// Cyrillic + Greek codepoints that have a basic-Latin lookalike (Unicode TR39
|
|
50
|
+
// confusables, common subset). A foreign letter only counts toward the
|
|
51
|
+
// confusable signal when it is in this set — Greek math operators with no Latin
|
|
52
|
+
// twin (Δ Σ Π Ω Φ Θ Λ Ξ Ψ Γ δ π ω …) are deliberately excluded so legit
|
|
53
|
+
// notation does not false-positive.
|
|
54
|
+
const _CONFUSABLE_FOREIGN: ReadonlySet<number> = new Set([
|
|
55
|
+
// Cyrillic lowercase ↔ Latin
|
|
56
|
+
0x0430 /*а→a*/, 0x0435 /*е→e*/, 0x043e /*о→o*/, 0x0440 /*р→p*/, 0x0441 /*с→c*/,
|
|
57
|
+
0x0443 /*у→y*/, 0x0445 /*х→x*/, 0x0455 /*ѕ→s*/, 0x0456 /*і→i*/, 0x0458 /*ј→j*/,
|
|
58
|
+
0x04bb /*һ→h*/, 0x0501 /*ԁ→d*/, 0x051b /*ԛ→q*/, 0x0577 /*no*/,
|
|
59
|
+
// Cyrillic uppercase ↔ Latin
|
|
60
|
+
0x0410 /*А→A*/, 0x0412 /*В→B*/, 0x0415 /*Е→E*/, 0x041a /*К→K*/, 0x041c /*М→M*/,
|
|
61
|
+
0x041d /*Н→H*/, 0x041e /*О→O*/, 0x0420 /*Р→P*/, 0x0421 /*С→C*/, 0x0422 /*Т→T*/,
|
|
62
|
+
0x0423 /*У→Y*/, 0x0425 /*Х→X*/, 0x0405 /*Ѕ→S*/, 0x0406 /*І→I*/, 0x0408 /*Ј→J*/,
|
|
63
|
+
// Greek lowercase ↔ Latin
|
|
64
|
+
0x03b1 /*α→a*/, 0x03b5 /*ε→e*/, 0x03bf /*ο→o*/, 0x03bd /*ν→v*/, 0x03c1 /*ρ→p*/,
|
|
65
|
+
0x03c5 /*υ→u*/, 0x03c7 /*χ→x*/, 0x03ba /*κ→k*/,
|
|
66
|
+
// Greek uppercase ↔ Latin (only those with a real Latin twin)
|
|
67
|
+
0x0391 /*Α→A*/, 0x0392 /*Β→B*/, 0x0395 /*Ε→E*/, 0x0396 /*Ζ→Z*/, 0x0397 /*Η→H*/,
|
|
68
|
+
0x0399 /*Ι→I*/, 0x039a /*Κ→K*/, 0x039c /*Μ→M*/, 0x039d /*Ν→N*/, 0x039f /*Ο→O*/,
|
|
69
|
+
0x03a1 /*Ρ→P*/, 0x03a4 /*Τ→T*/, 0x03a5 /*Υ→Y*/, 0x03a7 /*Χ→X*/, 0x0392 /*Β→B*/,
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
type ScriptName = 'latin' | 'cyrillic' | 'greek' | 'other';
|
|
73
|
+
|
|
74
|
+
function _script_of(ch: string): ScriptName {
|
|
75
|
+
if (_LATIN.test(ch)) return 'latin';
|
|
76
|
+
if (_CYRILLIC.test(ch)) return 'cyrillic';
|
|
77
|
+
if (_GREEK.test(ch)) return 'greek';
|
|
78
|
+
return 'other';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Classify a single token. Returns the offending mixed-script descriptor when
|
|
83
|
+
* the token matches the homoglyph signature, else null.
|
|
84
|
+
*/
|
|
85
|
+
export function _classify_token(token: string): string | null {
|
|
86
|
+
let latin = 0;
|
|
87
|
+
let cyrillic = 0;
|
|
88
|
+
let greek = 0;
|
|
89
|
+
let letters = 0;
|
|
90
|
+
for (const ch of token) {
|
|
91
|
+
if (!_LETTER.test(ch)) continue; // skip combining marks / digits for script vote
|
|
92
|
+
letters += 1;
|
|
93
|
+
const script = _script_of(ch);
|
|
94
|
+
if (script === 'latin') {
|
|
95
|
+
latin += 1;
|
|
96
|
+
} else if (script === 'cyrillic' || script === 'greek') {
|
|
97
|
+
// Only confusable foreign letters (TR39) count — math operators with
|
|
98
|
+
// no Latin twin are ignored, so legit notation never trips.
|
|
99
|
+
if (_CONFUSABLE_FOREIGN.has(ch.codePointAt(0) as number)) {
|
|
100
|
+
if (script === 'cyrillic') cyrillic += 1;
|
|
101
|
+
else greek += 1;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (letters < MIN_LETTERS) return null;
|
|
106
|
+
const foreign = cyrillic + greek;
|
|
107
|
+
if (latin === 0 || foreign === 0) return null; // single-script (or no Latin) → legit
|
|
108
|
+
if (latin <= foreign) return null; // majority must be Latin (foreign word ≠ attack)
|
|
109
|
+
const which = cyrillic > 0 && greek > 0
|
|
110
|
+
? 'cyrillic+greek'
|
|
111
|
+
: cyrillic > 0
|
|
112
|
+
? 'cyrillic'
|
|
113
|
+
: 'greek';
|
|
114
|
+
return `latin+${which} (${latin} latin / ${foreign} foreign-confusable)`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function _scan(sf: sl.ScannedFile): sl.Finding[] {
|
|
118
|
+
if (sf.pragma_allows(CHECK)) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
const out: sl.Finding[] = [];
|
|
122
|
+
for (const [lineno, text] of sf.iter_lines({ skip_example_fence: true })) {
|
|
123
|
+
const tokens = text.match(_TOKEN);
|
|
124
|
+
if (tokens === null) continue;
|
|
125
|
+
for (const tok of tokens) {
|
|
126
|
+
const desc = _classify_token(tok);
|
|
127
|
+
if (desc !== null) {
|
|
128
|
+
out.push(
|
|
129
|
+
new sl.Finding(
|
|
130
|
+
sf.rel,
|
|
131
|
+
lineno,
|
|
132
|
+
CHECK,
|
|
133
|
+
'HIGH',
|
|
134
|
+
`mixed-script confusable token "${tok}" — ${desc}`,
|
|
135
|
+
sf.weight,
|
|
136
|
+
),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
interface Args {
|
|
145
|
+
json: boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function _argError(msg: string): never {
|
|
149
|
+
process.stderr.write('usage: lint_confusables [-h] [--json]\n');
|
|
150
|
+
process.stderr.write(`lint_confusables: error: ${msg}\n`);
|
|
151
|
+
process.exit(2);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function parse_args(argv: readonly string[]): Args {
|
|
155
|
+
const out: Args = { json: false };
|
|
156
|
+
const extra: string[] = [];
|
|
157
|
+
for (const a of argv) {
|
|
158
|
+
if (a === '-h' || a === '--help') {
|
|
159
|
+
process.stdout.write('usage: lint_confusables [-h] [--json]\n');
|
|
160
|
+
process.exit(0);
|
|
161
|
+
} else if (a === '--json') {
|
|
162
|
+
out.json = true;
|
|
163
|
+
} else {
|
|
164
|
+
extra.push(a);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (extra.length > 0) {
|
|
168
|
+
_argError(`unrecognized arguments: ${extra.join(' ')}`);
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function main(argv: readonly string[] | null = null): number {
|
|
174
|
+
const args = parse_args(argv ?? process.argv.slice(2));
|
|
175
|
+
|
|
176
|
+
const findings: sl.Finding[] = [];
|
|
177
|
+
for (const sf of sl.iter_corpus()) {
|
|
178
|
+
for (const h of _scan(sf)) {
|
|
179
|
+
findings.push(h);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (args.json) {
|
|
184
|
+
const payload = sl.py_json_dumps_indent2(findings.map((f) => f.toDict()));
|
|
185
|
+
process.stdout.write(payload + '\n');
|
|
186
|
+
return findings.some((f) => f.is_fail) ? 1 : 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return sl.report(findings, { check_label: 'mixed-script-confusable' });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const _isCliEntry =
|
|
193
|
+
process.argv[1] !== undefined &&
|
|
194
|
+
import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href;
|
|
195
|
+
if (_isCliEntry) {
|
|
196
|
+
process.exitCode = main();
|
|
197
|
+
}
|