@event4u/agent-config 9.9.0 → 9.10.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 +1 -1
- package/CHANGELOG.md +153 -194
- package/README.md +1 -1
- package/dist/agent-src/commands/agent-status.md +12 -11
- package/dist/agent-src/commands/agents/user/accept.md +115 -30
- package/dist/agent-src/commands/agents/user/delete.md +147 -0
- package/dist/agent-src/commands/agents/user/review.md +65 -28
- package/dist/agent-src/commands/agents/user/show.md +82 -29
- package/dist/agent-src/commands/agents/user/update.md +2 -2
- package/dist/agent-src/commands/agents/user.md +16 -3
- package/dist/agent-src/commands/check-current-md.md +0 -10
- package/dist/agent-src/commands/condense.md +28 -97
- package/dist/agent-src/commands/cost/report.md +7 -0
- package/dist/agent-src/commands/fix/portability.md +0 -8
- package/dist/agent-src/commands/fix/refs.md +0 -8
- package/dist/agent-src/commands/humanize.md +2 -2
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/memory/load.md +11 -0
- package/dist/agent-src/commands/optimize/skills.md +1 -1
- package/dist/agent-src/commands/pr/create.md +4 -4
- package/dist/agent-src/commands/profile/show.md +3 -3
- package/dist/agent-src/commands/rule-compliance-audit.md +5 -4
- package/dist/agent-src/commands/security-audit-config.md +1 -1
- package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
- package/dist/agent-src/commands/tdd.md +21 -0
- package/dist/agent-src/commands/team/delegate.md +2 -2
- package/dist/agent-src/commands/team-knowledge/bootstrap.md +9 -8
- package/dist/agent-src/commands/team-knowledge/consolidate.md +8 -7
- package/dist/agent-src/commands/team.md +4 -1
- package/dist/agent-src/commands/upstream-contribute.md +0 -1
- package/dist/agent-src/contexts/authority/commit-mechanics.md +7 -0
- package/dist/agent-src/contexts/authority/destructive-mechanics.md +16 -0
- package/dist/agent-src/contexts/authority/scope-mechanics.md +61 -0
- package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +20 -18
- package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/source-of-truth-mechanics.md +9 -10
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +11 -0
- package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +26 -15
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +67 -37
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-examples.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +7 -6
- package/dist/agent-src/contexts/execution/evidence-discipline.md +92 -77
- package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +22 -21
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +24 -0
- package/dist/agent-src/contexts/execution/project-intelligence.md +122 -103
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +23 -21
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +5 -5
- package/dist/agent-src/contexts/execution/subagent-routing.md +11 -0
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +13 -13
- package/dist/agent-src/contexts/execution/subagent-steering.md +36 -34
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
- package/dist/agent-src/contexts/execution/user-memory-channels.md +189 -0
- package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -0
- package/dist/agent-src/contexts/model-recommendations.md +3 -2
- package/dist/agent-src/contexts/subagent-configuration.md +3 -3
- package/dist/agent-src/ghostwriter/README.md +2 -2
- package/dist/agent-src/packs/README.md +1 -1
- package/dist/agent-src/personas/README.md +5 -5
- package/dist/agent-src/personas/_template-specialist/persona.md +3 -3
- package/dist/agent-src/personas/backend-architect.md +24 -23
- package/dist/agent-src/personas/eloquent-tamer.md +30 -30
- package/dist/agent-src/personas/frontend-engineer.md +30 -30
- package/dist/agent-src/personas/product-owner.md +41 -38
- package/dist/agent-src/personas/qa.md +13 -13
- package/dist/agent-src/personas/security-engineer.md +22 -22
- package/dist/agent-src/presets/README.md +3 -3
- package/dist/agent-src/profiles/README.md +3 -3
- package/dist/agent-src/rules/active-remediation.md +2 -2
- package/dist/agent-src/rules/artifact-engagement-recording.md +4 -4
- package/dist/agent-src/rules/ask-when-uncertain.md +0 -4
- package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -4
- package/dist/agent-src/rules/code-comment-discipline.md +1 -1
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/commit-policy.md +4 -9
- package/dist/agent-src/rules/communication-through-line.md +5 -5
- package/dist/agent-src/rules/decision-revisit-gate.md +1 -1
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +1 -1
- package/dist/agent-src/rules/external-code-graph-interop.md +1 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +43 -7
- package/dist/agent-src/rules/finance-safety-floor.md +1 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -3
- package/dist/agent-src/rules/history-discipline.md +1 -1
- package/dist/agent-src/rules/legal-safety-floor.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +5 -5
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +10 -8
- package/dist/agent-src/rules/media-governance-routing.md +13 -13
- package/dist/agent-src/rules/media-sync-ground-truth.md +29 -11
- package/dist/agent-src/rules/no-cheap-questions.md +7 -7
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +29 -18
- package/dist/agent-src/rules/non-destructive-by-default.md +5 -23
- package/dist/agent-src/rules/onboarding-gate.md +14 -4
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/prefer-enums-over-literals.md +9 -9
- package/dist/agent-src/rules/preservation-guard.md +10 -2
- package/dist/agent-src/rules/question-not-instruction.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +6 -6
- package/dist/agent-src/rules/rule-type-governance.md +1 -1
- package/dist/agent-src/rules/scale-discipline.md +1 -1
- package/dist/agent-src/rules/scope-control.md +1 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +17 -11
- package/dist/agent-src/rules/senior-engineering-discipline.md +17 -17
- package/dist/agent-src/rules/session-canary.md +1 -1
- package/dist/agent-src/rules/skill-quality.md +1 -1
- package/dist/agent-src/rules/source-confidentiality.md +21 -19
- package/dist/agent-src/rules/source-of-truth.md +6 -5
- package/dist/agent-src/rules/spreadsheet-source-quality.md +2 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
- package/dist/agent-src/rules/think-before-action.md +5 -5
- package/dist/agent-src/rules/token-budget-discipline.md +5 -3
- package/dist/agent-src/rules/token-efficiency.md +2 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -4
- package/dist/agent-src/rules/user-interaction.md +12 -0
- package/dist/agent-src/rules/verify-before-complete.md +4 -24
- package/dist/agent-src/skills/adversarial-review/SKILL.md +2 -2
- package/dist/agent-src/skills/agent-security-review/SKILL.md +52 -45
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +2 -2
- package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +20 -20
- package/dist/agent-src/skills/ai-council/SKILL.md +185 -128
- package/dist/agent-src/skills/analysis-skill-router/SKILL.md +3 -3
- package/dist/agent-src/skills/api-endpoint/SKILL.md +2 -2
- package/dist/agent-src/skills/artisan-commands/SKILL.md +2 -2
- package/dist/agent-src/skills/async-python-patterns/SKILL.md +8 -7
- package/dist/agent-src/skills/authz-review/SKILL.md +16 -15
- package/dist/agent-src/skills/aws-infrastructure/SKILL.md +5 -5
- package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +30 -12
- package/dist/agent-src/skills/code-intelligence/SKILL.md +0 -1
- package/dist/agent-src/skills/code-intelligence/evals/triggers.json +52 -0
- package/dist/agent-src/skills/code-review/SKILL.md +6 -6
- package/dist/agent-src/skills/command-routing/SKILL.md +5 -4
- package/dist/agent-src/skills/composer-packages/SKILL.md +2 -2
- package/dist/agent-src/skills/condense-memory/SKILL.md +43 -41
- package/dist/agent-src/skills/context-document/SKILL.md +23 -21
- package/dist/agent-src/skills/copilot-config/SKILL.md +6 -1
- package/dist/agent-src/skills/decision-record/SKILL.md +20 -18
- package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
- package/dist/agent-src/skills/design-review/SKILL.md +15 -14
- package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +28 -25
- package/dist/agent-src/skills/devcontainer/SKILL.md +2 -2
- package/dist/agent-src/skills/docker/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/evals/triggers.json +52 -0
- package/dist/agent-src/skills/emit-tickets/SKILL.md +2 -2
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +2 -2
- package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +0 -1
- package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +52 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +6 -5
- package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +3 -3
- package/dist/agent-src/skills/flux/SKILL.md +1 -1
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +13 -13
- package/dist/agent-src/skills/git-workflow/SKILL.md +33 -33
- package/dist/agent-src/skills/grafana/SKILL.md +5 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +83 -66
- package/dist/agent-src/skills/humanizer/data/patterns.md +14 -14
- package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +4 -4
- package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +82 -37
- package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +17 -5
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +63 -25
- package/dist/agent-src/skills/judge-security-auditor/SKILL.md +2 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +72 -28
- package/dist/agent-src/skills/laravel-horizon/SKILL.md +5 -0
- package/dist/agent-src/skills/laravel-mail/SKILL.md +5 -4
- package/dist/agent-src/skills/laravel-middleware/SKILL.md +5 -4
- package/dist/agent-src/skills/laravel-notifications/SKILL.md +10 -9
- package/dist/agent-src/skills/laravel-pennant/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-pulse/SKILL.md +9 -8
- package/dist/agent-src/skills/laravel-reverb/SKILL.md +6 -5
- package/dist/agent-src/skills/laravel-scheduling/SKILL.md +6 -1
- package/dist/agent-src/skills/laravel-validation/SKILL.md +12 -0
- package/dist/agent-src/skills/launch-readiness/SKILL.md +1 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +7 -7
- package/dist/agent-src/skills/learning-tutor/SKILL.md +44 -43
- package/dist/agent-src/skills/learning-tutor/evals/triggers.json +52 -0
- package/dist/agent-src/skills/license-compliance-audit/SKILL.md +7 -7
- package/dist/agent-src/skills/license-compliance-borrow-check/SKILL.md +3 -3
- package/dist/agent-src/skills/license-compliance-credits/SKILL.md +4 -4
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +0 -1
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +69 -64
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -6
- package/dist/agent-src/skills/pdf-tools/evals/triggers.json +52 -0
- package/dist/agent-src/skills/performance-analysis/SKILL.md +7 -3
- package/dist/agent-src/skills/persona-improvement/SKILL.md +0 -2
- package/dist/agent-src/skills/persona-improvement/evals/triggers.json +52 -0
- package/dist/agent-src/skills/php-coder/SKILL.md +10 -0
- package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +129 -120
- package/dist/agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +36 -35
- package/dist/agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +45 -41
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +4 -4
- package/dist/agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
- package/dist/agent-src/skills/project-analysis-react/SKILL.md +1 -1
- package/dist/agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
- package/dist/agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
- package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-validator/SKILL.md +39 -39
- package/dist/agent-src/skills/quality-tools/SKILL.md +15 -15
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +55 -19
- package/dist/agent-src/skills/react-shadcn-ui/reference/registry.md +29 -27
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +2 -2
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +25 -25
- package/dist/agent-src/skills/recursive-verification/SKILL.md +6 -5
- package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +20 -2
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-management/SKILL.md +80 -66
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +84 -77
- package/dist/agent-src/skills/rule-refactor/SKILL.md +1 -1
- package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +52 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +26 -9
- package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +38 -16
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +14 -11
- package/dist/agent-src/skills/skill-writing/SKILL.md +9 -8
- package/dist/agent-src/skills/song-to-script/SKILL.md +93 -85
- package/dist/agent-src/skills/sql-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +4 -3
- package/dist/agent-src/skills/standards-from-config/SKILL.md +61 -43
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +22 -8
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +28 -2
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +13 -13
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +22 -21
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/technical-specification/SKILL.md +5 -0
- package/dist/agent-src/skills/terraform/SKILL.md +2 -2
- package/dist/agent-src/skills/terragrunt/SKILL.md +8 -8
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +19 -13
- package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +0 -1
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +9 -9
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -1
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +4 -6
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +67 -61
- package/dist/agent-src/skills/video-director/SKILL.md +7 -7
- package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +3 -3
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/contexts/knowledge-pages.md +47 -45
- package/dist/agent-src/templates/contexts/lesson-card.md +2 -2
- package/dist/agent-src/templates/contexts/tenant-boundaries.md +2 -2
- package/dist/agent-src/templates/contexts.md +1 -1
- package/dist/agent-src/templates/features.md +1 -1
- package/dist/agent-src/templates/roadmaps.md +125 -116
- package/dist/agent-src/templates/rule.md +2 -1
- package/dist/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/dist/agent-src/templates/scripts/tier_usage_report.ts +2 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
- package/dist/agent-src/user-types/README.md +8 -8
- package/dist/agent-src/user-types/galabau-field-crew.md +34 -33
- package/dist/agent-src/user-types/metalworking-shop.md +35 -34
- package/dist/agent-src/user-types/truck-driver.md +22 -20
- package/dist/cli/python/workspace_roles.js +2 -2
- package/dist/cli/python/workspace_roles.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +88 -62
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +186 -12
- package/dist/install/install.mjs +8 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1199 -857
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/compile_time_toggles.js +48 -0
- package/dist/scripts/_lib/compile_time_toggles.js.map +1 -0
- package/dist/scripts/condense.js +234 -217
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +4 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/userMd/utils.js +30 -0
- package/dist/shared/userMd/utils.js.map +1 -1
- package/dist/ui/assets/index-BpSQt5vm.js.map +1 -1
- package/docs/guidelines/agent-infra/api-cost-levers.md +56 -5
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +93 -33
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/src/agent-src/templates/scripts/tier_usage_report.ts +2 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
- package/src/config/agent-settings.template.yml +32 -2
- package/src/config/ci-local-parity.yml +142 -0
- package/src/config/gate-coverage.yml +127 -0
- package/src/config/preamble-payload-budget.json +44 -0
- package/src/scripts/_cli/cmd_doctor.ts +78 -2
- package/src/scripts/_lib/agent_user_profile.ts +381 -0
- package/src/scripts/_lib/agents_overlay.ts +9 -0
- package/src/scripts/_lib/anchor_eval.ts +311 -0
- package/src/scripts/_lib/cc_transcript.ts +316 -0
- package/src/scripts/_lib/compile_time_toggles.ts +79 -0
- package/src/scripts/_lib/confusables.ts +101 -0
- package/src/scripts/_lib/duplicate_scope_census.ts +77 -0
- package/src/scripts/_lib/managed_agents_folder.ts +181 -0
- package/src/scripts/_lib/payload_hash_drift.ts +126 -0
- package/src/scripts/_lib/preservation_migration.ts +291 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +166 -2
- package/src/scripts/_lib/scan_scope.ts +115 -0
- package/src/scripts/_lib/user_global_memory_audit.ts +187 -0
- package/src/scripts/_lib/user_global_observations.ts +830 -0
- package/src/scripts/_lib/user_global_revocations.ts +110 -0
- package/src/scripts/_lib/user_memory_gate_counters.ts +291 -0
- package/src/scripts/ai_council/blind_review.ts +0 -0
- package/src/scripts/ai_council/budget_guard.ts +90 -11
- package/src/scripts/ai_council/bundler.ts +2 -2
- package/src/scripts/ai_council/clients.ts +59 -3
- package/src/scripts/ai_council/config.ts +38 -0
- package/src/scripts/ai_council/orchestrator.ts +54 -9
- package/src/scripts/ai_team/team_dispatch.ts +17 -6
- package/src/scripts/anchor_eval_falsify.ts +198 -0
- package/src/scripts/anchor_scoring_run.ts +239 -0
- package/src/scripts/annotate_discovery.ts +1 -65
- package/src/scripts/bench_quality_run.ts +168 -4
- package/src/scripts/cache_realization_report.ts +782 -0
- package/src/scripts/check_artefact_count_messaging.ts +5 -1
- package/src/scripts/check_augment_description_cap.ts +15 -4
- package/src/scripts/check_ci_local_parity.ts +317 -0
- package/src/scripts/check_condensation.ts +96 -191
- package/src/scripts/check_context_paths.ts +38 -9
- package/src/scripts/check_gate_coverage.ts +299 -0
- package/src/scripts/check_iron_law_prominence.ts +22 -1
- package/src/scripts/check_kernel_prefix_stability.ts +0 -0
- package/src/scripts/check_no_new_legacy_path.ts +16 -6
- package/src/scripts/check_no_roadmap_refs.ts +22 -9
- package/src/scripts/check_originality_freshness.ts +167 -0
- package/src/scripts/check_preamble_payload_budget.ts +130 -0
- package/src/scripts/check_proposal.ts +0 -0
- package/src/scripts/check_references.ts +0 -1
- package/src/scripts/check_safety_floor_untouched.ts +171 -24
- package/src/scripts/check_site_links.ts +62 -3
- package/src/scripts/ci_status.ts +0 -0
- package/src/scripts/cluster_near_miss_patterns.ts +0 -0
- package/src/scripts/code_graph/build.ts +0 -0
- package/src/scripts/command_suggester/types.ts +0 -0
- package/src/scripts/compile_router.ts +10 -14
- package/src/scripts/condense.sh +3 -4
- package/src/scripts/condense.ts +247 -228
- package/src/scripts/cost/track.mjs +168 -33
- package/src/scripts/cost_summary.ts +33 -1
- package/src/scripts/council_cli.ts +45 -3
- package/src/scripts/discovery_graph.ts +0 -0
- package/src/scripts/encoding_corpus.ts +500 -0
- package/src/scripts/encoding_corpus_report.ts +216 -0
- package/src/scripts/generate_index.ts +19 -2
- package/src/scripts/install-hooks.sh +2 -2
- package/src/scripts/learning_sidecar.ts +0 -0
- package/src/scripts/lint_confusables.ts +10 -72
- package/src/scripts/lint_featured_skills.ts +0 -0
- package/src/scripts/lint_hidden_unicode.ts +208 -0
- package/src/scripts/lint_load_context.ts +17 -5
- package/src/scripts/lint_new_skill_gate.ts +9 -3
- package/src/scripts/lint_no_python_twin_rationale.ts +17 -2
- package/src/scripts/lint_originality.ts +1 -1
- package/src/scripts/lint_skill_originality.ts +1 -1
- package/src/scripts/lint_ticket_buildable.ts +1 -1
- package/src/scripts/mcp_server/tools.ts +4 -4
- package/src/scripts/measure_scope_dedup.ts +224 -0
- package/src/scripts/memory_lookup.ts +0 -0
- package/src/scripts/mine_session.ts +98 -0
- package/src/scripts/orchestration_payload_hash_drift.ts +145 -0
- package/src/scripts/preamble_byte_census.ts +574 -0
- package/src/scripts/probe_skill_registration.ts +2 -2
- package/src/scripts/redact_hook_capture.ts +13 -0
- package/src/scripts/release.ts +65 -10
- package/src/scripts/router_telemetry.ts +1 -1
- package/src/scripts/second_brain_retrieval.ts +14 -4
- package/src/scripts/skill_linter.ts +5 -0
- package/src/scripts/surface-tiers.yml +2 -0
- package/src/scripts/validate_pack_yaml.ts +0 -0
- package/src/server/schemas/settings.ts +8 -0
- package/src/shared/userMd/utils.ts +31 -0
- package/dist/agent-src/rules/telegraph-speak.md +0 -87
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-time rule toggles — the single definition, shared by the router compiler
|
|
3
|
+
* and the projector.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS FILE EXISTS
|
|
6
|
+
* --------------------
|
|
7
|
+
* The map used to live only in `compile_router.ts`, which meant a disabled rule was
|
|
8
|
+
* dropped from `dist/router.json` while its **body still shipped** as a file in
|
|
9
|
+
* `dist/agent-src/rules/` (and through the `.claude/rules/` symlink). ADR
|
|
10
|
+
* `telegraph/0002` originally claimed that flipping the toggle gave "zero-cost
|
|
11
|
+
* dormancy". That was measured and found half wrong on 2026-07-29: the router entry
|
|
12
|
+
* governs *trigger-routing*; **file existence governs always-loaded injection**, and
|
|
13
|
+
* the host reads the file — a maintainer session's context listed the body verbatim
|
|
14
|
+
* as "project instructions", never having consulted the router.
|
|
15
|
+
*
|
|
16
|
+
* Two surfaces, one switch. Sharing the definition is what lets the projector honour
|
|
17
|
+
* it, so `speak: false` means what the ADR assumed instead of the ADR being weakened
|
|
18
|
+
* to match a partial implementation.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* HOW A RULE GETS HERE — the dormancy routing (road-to-cache-economy Phase 3)
|
|
23
|
+
* --------------------------------------------------------------------------
|
|
24
|
+
* A rule body is re-written on EVERY subagent spawn, so an always-loaded rule
|
|
25
|
+
* that is not earning its keep is paid per spawn, not once. That makes "should
|
|
26
|
+
* this rule be dormant?" a real question — and this map is the ONLY place the
|
|
27
|
+
* answer may land. The route, in order:
|
|
28
|
+
*
|
|
29
|
+
* 1. **Candidate** — `preamble_byte_census` ranks always-loaded rules by
|
|
30
|
+
* per-spawn token cost (`--top`). A candidate is a number, never an
|
|
31
|
+
* impression: telegraph-speak was ~982 tokens.
|
|
32
|
+
* 2. **Evidence** — the same bar telegraph-speak had to clear: an output-side
|
|
33
|
+
* bench showing the rule does not pay for itself, judged against the
|
|
34
|
+
* kill-criterion, BEFORE dormancy. A preference is not evidence, and
|
|
35
|
+
* "it looks verbose" is not a measurement.
|
|
36
|
+
* 3. **Landing** — a new entry in the map below, keyed on a real setting the
|
|
37
|
+
* consumer can flip back. Never a fifth toggle axis: this predicate already
|
|
38
|
+
* has four consumers (the router compiler, the dist writer, `check_sync`,
|
|
39
|
+
* and the per-tool symlink generator), and a rule wired into three of four
|
|
40
|
+
* is how the last attempt blocked its own push.
|
|
41
|
+
*
|
|
42
|
+
* What is explicitly NOT this route: dropping a rule from the router while its
|
|
43
|
+
* body still ships (that was the measured half-truth this file exists to fix),
|
|
44
|
+
* and gating bodies behind triggers wholesale — that is thin projection, which
|
|
45
|
+
* failed a 48% quality floor at 36.2% and stays disabled.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/** Loose settings shape — the toggles only ever read nested plain objects. */
|
|
49
|
+
export type ToggleSettings = Record<string, unknown>;
|
|
50
|
+
|
|
51
|
+
/** rule-id → predicate. A rule is emitted (router AND projection) only when its
|
|
52
|
+
* predicate returns true. A rule absent from this map is always emitted. */
|
|
53
|
+
export const COMPILE_TIME_TOGGLES: Record<string, (s: ToggleSettings) => boolean> = {
|
|
54
|
+
// `speak` defaults FALSE (dormant) per docs/adrs/telegraph/0002 — the absent-key
|
|
55
|
+
// fallback used to be `true`, which silently contradicted ADR 0001 (accepted,
|
|
56
|
+
// "default off until bench"). Measured basis: median vs_terse −9.27% (API) /
|
|
57
|
+
// −5.47% (exact cl100k_base) — telegraph emits MORE than a plain "be terse".
|
|
58
|
+
// Opt back in with an explicit `telegraph.speak: true` once an output-side bench
|
|
59
|
+
// clears the kill-criterion bar. `enabled` keeps its true default: it is the
|
|
60
|
+
// family master switch, and flipping it would silence sibling telegraph settings
|
|
61
|
+
// that were never measured negative.
|
|
62
|
+
//
|
|
63
|
+
// This predicate deliberately does NOT read `speak_scope`. That key disables the
|
|
64
|
+
// rule's *behaviour* and never removed its token cost — the trap the measurement
|
|
65
|
+
// exposed.
|
|
66
|
+
'telegraph-speak': (s: ToggleSettings): boolean => {
|
|
67
|
+
const tg = (s['telegraph'] as ToggleSettings | undefined) ?? {};
|
|
68
|
+
const enabled = tg['enabled'] === undefined ? true : tg['enabled'];
|
|
69
|
+
const speak = tg['speak'] === undefined ? false : tg['speak'];
|
|
70
|
+
return Boolean(enabled) && Boolean(speak);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** True when the rule may be emitted. Unknown ids are always emitted — the map is an
|
|
75
|
+
* opt-in list of gated rules, never an allowlist of permitted ones. */
|
|
76
|
+
export function rule_is_compile_enabled(rule_id: string, settings: ToggleSettings): boolean {
|
|
77
|
+
const predicate = COMPILE_TIME_TOGGLES[rule_id];
|
|
78
|
+
return predicate === undefined ? true : predicate(settings);
|
|
79
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visible mixed-script confusable signature — the ONE definition in the tree.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `lint_confusables.ts` so the authoring-time linter and the
|
|
5
|
+
* runtime encoding scanner share one table and one decision rule
|
|
6
|
+
* (road-to-runtime-encoding-hardening Phase 3). Two copies of a confusable set
|
|
7
|
+
* is exactly the drift this extraction prevents: a codepoint added to one and
|
|
8
|
+
* not the other means the two surfaces disagree about what a homoglyph is.
|
|
9
|
+
*
|
|
10
|
+
* The dependency direction matters. This module imports NOTHING — no `fs`, no
|
|
11
|
+
* lint framework — so the runtime retrieval path can use it without pulling the
|
|
12
|
+
* authoring-time lint infrastructure into a request.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** A token needs this many letters before the signature can fire. */
|
|
16
|
+
export const MIN_LETTERS = 3;
|
|
17
|
+
|
|
18
|
+
// Unicode-script classifiers via property escapes (requires the `u` flag).
|
|
19
|
+
const _LATIN = /\p{Script=Latin}/u;
|
|
20
|
+
const _CYRILLIC = /\p{Script=Cyrillic}/u;
|
|
21
|
+
const _GREEK = /\p{Script=Greek}/u;
|
|
22
|
+
const _LETTER = /\p{L}/u;
|
|
23
|
+
|
|
24
|
+
/** A "token" is a maximal run of letters / combining marks / decimal digits. */
|
|
25
|
+
export const TOKEN_RE = /[\p{L}\p{M}\p{Nd}]+/gu;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Cyrillic + Greek codepoints that have a basic-Latin lookalike (Unicode TR39
|
|
29
|
+
* confusables, common subset). A foreign letter only counts toward the
|
|
30
|
+
* confusable signal when it is in this set — Greek math operators with no Latin
|
|
31
|
+
* twin (Δ Σ Π Ω Φ Θ Λ Ξ Ψ Γ δ π ω …) are deliberately excluded so legit
|
|
32
|
+
* notation does not false-positive.
|
|
33
|
+
*/
|
|
34
|
+
export const CONFUSABLE_FOREIGN: ReadonlySet<number> = new Set([
|
|
35
|
+
// Cyrillic lowercase ↔ Latin
|
|
36
|
+
0x0430 /*а→a*/, 0x0435 /*е→e*/, 0x043e /*о→o*/, 0x0440 /*р→p*/, 0x0441 /*с→c*/,
|
|
37
|
+
0x0443 /*у→y*/, 0x0445 /*х→x*/, 0x0455 /*ѕ→s*/, 0x0456 /*і→i*/, 0x0458 /*ј→j*/,
|
|
38
|
+
0x04bb /*һ→h*/, 0x0501 /*ԁ→d*/, 0x051b /*ԛ→q*/, 0x0577 /*no*/,
|
|
39
|
+
// Cyrillic uppercase ↔ Latin
|
|
40
|
+
0x0410 /*А→A*/, 0x0412 /*В→B*/, 0x0415 /*Е→E*/, 0x041a /*К→K*/, 0x041c /*М→M*/,
|
|
41
|
+
0x041d /*Н→H*/, 0x041e /*О→O*/, 0x0420 /*Р→P*/, 0x0421 /*С→C*/, 0x0422 /*Т→T*/,
|
|
42
|
+
0x0423 /*У→Y*/, 0x0425 /*Х→X*/, 0x0405 /*Ѕ→S*/, 0x0406 /*І→I*/, 0x0408 /*Ј→J*/,
|
|
43
|
+
// Greek lowercase ↔ Latin
|
|
44
|
+
0x03b1 /*α→a*/, 0x03b5 /*ε→e*/, 0x03bf /*ο→o*/, 0x03bd /*ν→v*/, 0x03c1 /*ρ→p*/,
|
|
45
|
+
0x03c5 /*υ→u*/, 0x03c7 /*χ→x*/, 0x03ba /*κ→k*/,
|
|
46
|
+
// Greek uppercase ↔ Latin (only those with a real Latin twin)
|
|
47
|
+
0x0391 /*Α→A*/, 0x0392 /*Β→B*/, 0x0395 /*Ε→E*/, 0x0396 /*Ζ→Z*/, 0x0397 /*Η→H*/,
|
|
48
|
+
0x0399 /*Ι→I*/, 0x039a /*Κ→K*/, 0x039c /*Μ→M*/, 0x039d /*Ν→N*/, 0x039f /*Ο→O*/,
|
|
49
|
+
0x03a1 /*Ρ→P*/, 0x03a4 /*Τ→T*/, 0x03a5 /*Υ→Y*/, 0x03a7 /*Χ→X*/, 0x0392 /*Β→B*/,
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
type ScriptName = 'latin' | 'cyrillic' | 'greek' | 'other';
|
|
53
|
+
|
|
54
|
+
function _script_of(ch: string): ScriptName {
|
|
55
|
+
if (_LATIN.test(ch)) return 'latin';
|
|
56
|
+
if (_CYRILLIC.test(ch)) return 'cyrillic';
|
|
57
|
+
if (_GREEK.test(ch)) return 'greek';
|
|
58
|
+
return 'other';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Classify a single token. Returns the offending mixed-script descriptor when
|
|
63
|
+
* the token matches the homoglyph signature, else null.
|
|
64
|
+
*
|
|
65
|
+
* The containment rules are the load-bearing part, and they are why this is one
|
|
66
|
+
* shared function rather than two similar ones: a Latin-majority token with at
|
|
67
|
+
* least one TR39-confusable foreign letter is the signal; a single-script token
|
|
68
|
+
* (a genuine Cyrillic or Greek word) is not; and a token whose foreign letters
|
|
69
|
+
* outnumber its Latin ones is a foreign word, not an attack.
|
|
70
|
+
*/
|
|
71
|
+
export function classifyToken(token: string): string | null {
|
|
72
|
+
let latin = 0;
|
|
73
|
+
let cyrillic = 0;
|
|
74
|
+
let greek = 0;
|
|
75
|
+
let letters = 0;
|
|
76
|
+
for (const ch of token) {
|
|
77
|
+
if (!_LETTER.test(ch)) continue; // skip combining marks / digits for script vote
|
|
78
|
+
letters += 1;
|
|
79
|
+
const script = _script_of(ch);
|
|
80
|
+
if (script === 'latin') {
|
|
81
|
+
latin += 1;
|
|
82
|
+
} else if (script === 'cyrillic' || script === 'greek') {
|
|
83
|
+
// Only confusable foreign letters (TR39) count — math operators with
|
|
84
|
+
// no Latin twin are ignored, so legit notation never trips.
|
|
85
|
+
if (CONFUSABLE_FOREIGN.has(ch.codePointAt(0) as number)) {
|
|
86
|
+
if (script === 'cyrillic') cyrillic += 1;
|
|
87
|
+
else greek += 1;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (letters < MIN_LETTERS) return null;
|
|
92
|
+
const foreign = cyrillic + greek;
|
|
93
|
+
if (latin === 0 || foreign === 0) return null; // single-script (or no Latin) → legit
|
|
94
|
+
if (latin <= foreign) return null; // majority must be Latin (foreign word ≠ attack)
|
|
95
|
+
const which = cyrillic > 0 && greek > 0
|
|
96
|
+
? 'cyrillic+greek'
|
|
97
|
+
: cyrillic > 0
|
|
98
|
+
? 'cyrillic'
|
|
99
|
+
: 'greek';
|
|
100
|
+
return `latin+${which} (${latin} latin / ${foreign} foreign-confusable)`;
|
|
101
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duplicate-scope rule census — the shared byte-comparison primitive behind
|
|
3
|
+
* both C-2 (`cache_realization_report.ts`'s `computeDuplicateScope`, which
|
|
4
|
+
* turns this into a share of subagent write volume) and the `doctor`
|
|
5
|
+
* `duplicate-scope-rules` health check (`_cli/cmd_doctor.ts`), so the two
|
|
6
|
+
* surfaces can never drift on what counts as "shared" or how a redundant
|
|
7
|
+
* copy's size is estimated.
|
|
8
|
+
*
|
|
9
|
+
* `road-to-cache-economy.md` Phase 3: the same 110 rule
|
|
10
|
+
* filenames observed at both `~/.claude/rules` (user scope) and
|
|
11
|
+
* `dist/agent-src/rules` (project scope) on this maintainer's own checkout —
|
|
12
|
+
* C-2 confirmed at 38.5% of subagent write volume. This module answers only
|
|
13
|
+
* "which filenames are shared, and how many redundant bytes do they cost" —
|
|
14
|
+
* the write-volume share and the doctor warning are each computed by their
|
|
15
|
+
* own caller from this raw census.
|
|
16
|
+
*
|
|
17
|
+
* Detection only. Never deletes, never rewrites a user's file — see
|
|
18
|
+
* `non-destructive-by-default`.
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'node:fs';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
|
|
23
|
+
export interface DuplicateScopeCensus {
|
|
24
|
+
evaluable: boolean;
|
|
25
|
+
reason?: string | undefined;
|
|
26
|
+
/** `.md` basenames present in BOTH directories, sorted. */
|
|
27
|
+
shared_filenames: string[];
|
|
28
|
+
/** Σ min(userBytes, projectBytes) over shared filenames — the conservative
|
|
29
|
+
* estimate of the redundant copy (the roadmap's byte census found the two
|
|
30
|
+
* scopes near-identical in size, so the min/max choice rarely matters). */
|
|
31
|
+
duplicate_chars: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* For every `.md` filename present in BOTH `userRulesDir` and
|
|
36
|
+
* `projectRulesDir`, the redundant copy is estimated as the SMALLER of the
|
|
37
|
+
* two files' byte sizes, summed across all shared filenames.
|
|
38
|
+
*/
|
|
39
|
+
export function censusDuplicateScope(userRulesDir: string, projectRulesDir: string): DuplicateScopeCensus {
|
|
40
|
+
if (!fs.existsSync(userRulesDir) || !fs.existsSync(projectRulesDir)) {
|
|
41
|
+
return {
|
|
42
|
+
evaluable: false,
|
|
43
|
+
reason: `one or both rule directories are missing (user: ${userRulesDir}, project: ${projectRulesDir})`,
|
|
44
|
+
shared_filenames: [],
|
|
45
|
+
duplicate_chars: 0,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const userFiles = new Set(fs.readdirSync(userRulesDir).filter((f) => f.endsWith('.md')));
|
|
50
|
+
const projectFiles = fs.readdirSync(projectRulesDir).filter((f) => f.endsWith('.md'));
|
|
51
|
+
|
|
52
|
+
const shared: string[] = [];
|
|
53
|
+
let duplicateChars = 0;
|
|
54
|
+
for (const f of projectFiles) {
|
|
55
|
+
if (!userFiles.has(f)) continue;
|
|
56
|
+
shared.push(f);
|
|
57
|
+
const a = fs.statSync(path.join(userRulesDir, f)).size;
|
|
58
|
+
const b = fs.statSync(path.join(projectRulesDir, f)).size;
|
|
59
|
+
duplicateChars += Math.min(a, b);
|
|
60
|
+
}
|
|
61
|
+
shared.sort();
|
|
62
|
+
|
|
63
|
+
if (shared.length === 0) {
|
|
64
|
+
return {
|
|
65
|
+
evaluable: false,
|
|
66
|
+
reason: 'no shared .md filenames between the two rule scopes — this checkout has no duplicate-scope install',
|
|
67
|
+
shared_filenames: [],
|
|
68
|
+
duplicate_chars: 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
evaluable: true,
|
|
74
|
+
shared_filenames: shared,
|
|
75
|
+
duplicate_chars: duplicateChars,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect whether a directory is a project whose `agents/` folder is managed
|
|
3
|
+
* by this package.
|
|
4
|
+
*
|
|
5
|
+
* `.agent-settings.yml` resolution and settings-cascade routing already have
|
|
6
|
+
* a project-root walker (`find_project_root_with_anchor` in
|
|
7
|
+
* `_lib/agent_settings.ts`), but that walker answers a different question —
|
|
8
|
+
* "where does the settings cascade start reading from" — and its `agents/`
|
|
9
|
+
* check exists only to pick a boundary anchor for that walk (its marker list
|
|
10
|
+
* mixes package-source-repo-only paths, e.g. `settings/.ai-council.yml`, with
|
|
11
|
+
* consumer-only paths). It also treats a bare `.git` anywhere in the ancestor
|
|
12
|
+
* chain as "a project was found", which is the right answer for "where do
|
|
13
|
+
* settings live" but the wrong answer for "is this THIS package's managed
|
|
14
|
+
* `agents/` folder" — a third-party repo with an unrelated `agents/`
|
|
15
|
+
* directory and its own `.git` would resolve to a root there too. No
|
|
16
|
+
* existing helper answers the narrower managed/unmanaged/not-a-project
|
|
17
|
+
* question this module exists for.
|
|
18
|
+
*
|
|
19
|
+
* Contract — pure, read-only, tolerant:
|
|
20
|
+
*
|
|
21
|
+
* - Never writes, never mutates, never touches the network.
|
|
22
|
+
* - Operates on the given `start` directory directly — it does not walk
|
|
23
|
+
* ancestors looking for a project root (that is the caller's job, e.g.
|
|
24
|
+
* via `find_project_root` when the caller only has a subdirectory).
|
|
25
|
+
* Keeping this helper non-walking keeps it a distinct primitive from the
|
|
26
|
+
* settings-root walker above rather than a second, subtly different copy
|
|
27
|
+
* of the same walk.
|
|
28
|
+
* - Silently tolerant of a missing/unreadable `start` — every check falls
|
|
29
|
+
* through to `false`, which resolves to `'not-a-project'`.
|
|
30
|
+
*/
|
|
31
|
+
import * as fs from 'node:fs';
|
|
32
|
+
import * as path from 'node:path';
|
|
33
|
+
|
|
34
|
+
import { SECTION_HEADER as _MANAGED_GITIGNORE_HEADER } from '../sync_gitignore.js';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Three-state answer — never a boolean, because "no `agents/` folder" and
|
|
38
|
+
* "no project at all" route differently downstream (an unmanaged repo is a
|
|
39
|
+
* candidate for adoption; a bare directory outside any repo is not a
|
|
40
|
+
* project the P-routing question even applies to).
|
|
41
|
+
*/
|
|
42
|
+
export type ManagedAgentsFolderStatus = 'managed' | 'unmanaged' | 'not-a-project';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Detection predicate — chosen after inspecting what the installer actually
|
|
46
|
+
* writes into a consumer project (verified against source, not invented):
|
|
47
|
+
*
|
|
48
|
+
* is_project := <start>/.git exists (file or directory — worktrees and
|
|
49
|
+
* submodules use a `.git` file, not a directory).
|
|
50
|
+
* has_agents := <start>/agents is a directory.
|
|
51
|
+
* has_marker := ANY of —
|
|
52
|
+
* (a) <start>/.gitignore contains the managed-block header line
|
|
53
|
+
* `# event4u/agent-config` (`SECTION_HEADER` in
|
|
54
|
+
* `sync_gitignore.ts`) — installed by `refresh --project` /
|
|
55
|
+
* `sync:gitignore`. Strongest signal: the literal package name, so
|
|
56
|
+
* a third-party repo carries it only if it also runs this package.
|
|
57
|
+
* (b) <start>/agents/overrides/ is a directory — scaffolded by
|
|
58
|
+
* `install.ts` for every consumer project (the "guaranteed
|
|
59
|
+
* minimal-consumer surface", ADR-020).
|
|
60
|
+
* (c) a resolvable `.agent-settings.yml` exists — canonical
|
|
61
|
+
* `<start>/agents/settings/.agent-settings.yml`, or the legacy
|
|
62
|
+
* `<start>/.agent-settings.yml` fallback (see
|
|
63
|
+
* `project_settings_path` in `_lib/agent_settings.ts`).
|
|
64
|
+
*
|
|
65
|
+
* status := has_agents && has_marker → 'managed'
|
|
66
|
+
* is_project (else) → 'unmanaged'
|
|
67
|
+
* otherwise → 'not-a-project'
|
|
68
|
+
*
|
|
69
|
+
* Rejected alternatives:
|
|
70
|
+
*
|
|
71
|
+
* - `agents/` existence alone (no marker). Rejected: this is exactly the
|
|
72
|
+
* false positive the roadmap phase calls out — an unrelated multi-agent
|
|
73
|
+
* framework repo, or any project that happens to name a directory
|
|
74
|
+
* `agents/`, would read as managed with zero package-specific evidence.
|
|
75
|
+
* - Reusing `find_project_root_with_anchor`'s `_AGENTS_DIR_MARKERS` list
|
|
76
|
+
* verbatim (`roadmaps`, `settings/.ai-council.yml`,
|
|
77
|
+
* `roadmaps-progress.md`, `overrides`). Rejected: two of those four
|
|
78
|
+
* (`settings/.ai-council.yml`, `roadmaps-progress.md`) are `pkg`-scope
|
|
79
|
+
* only per `docs/contracts/agents-layout.md`'s consumer-slim-profile
|
|
80
|
+
* table — they never appear in an installed consumer project, so
|
|
81
|
+
* requiring "any one" would under-detect nothing (they're just dead
|
|
82
|
+
* weight for the consumer case) but reusing the *function* would also
|
|
83
|
+
* inherit its `.git`-anchor and `.agent-settings.yml`-layer-fallback
|
|
84
|
+
* semantics, which answer "where is the settings root" rather than
|
|
85
|
+
* "is `agents/` managed" (see module docblock).
|
|
86
|
+
* - `agents/roadmaps/` as a marker. Rejected: it is listed as "Optional"
|
|
87
|
+
* even in the consumer-slim profile — a managed project with zero
|
|
88
|
+
* roadmaps yet (the common case right after install) would false-
|
|
89
|
+
* negative.
|
|
90
|
+
*/
|
|
91
|
+
function _existsAt(dir: string, ...segments: readonly string[]): boolean {
|
|
92
|
+
try {
|
|
93
|
+
fs.statSync(path.join(dir, ...segments));
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function _isDirAt(dir: string, ...segments: readonly string[]): boolean {
|
|
101
|
+
try {
|
|
102
|
+
return fs.statSync(path.join(dir, ...segments)).isDirectory();
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function _isFileAt(dir: string, ...segments: readonly string[]): boolean {
|
|
109
|
+
try {
|
|
110
|
+
return fs.statSync(path.join(dir, ...segments)).isFile();
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** `true` when `start` sits at the root of a git repository (or worktree). */
|
|
117
|
+
function _isGitProject(start: string): boolean {
|
|
118
|
+
// `.git` is a directory in a normal clone, a file in a worktree or
|
|
119
|
+
// submodule checkout — `statSync` (not `lstatSync`) is deliberate so a
|
|
120
|
+
// broken symlink named `.git` does not count as present.
|
|
121
|
+
return _existsAt(start, '.git');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** `true` when `<start>/.gitignore` carries the managed-block header line. */
|
|
125
|
+
function _hasManagedGitignoreBlock(start: string): boolean {
|
|
126
|
+
if (!_isFileAt(start, '.gitignore')) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
let text: string;
|
|
130
|
+
try {
|
|
131
|
+
text = fs.readFileSync(path.join(start, '.gitignore'), 'utf-8');
|
|
132
|
+
} catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return text
|
|
136
|
+
.split(/\r\n|\r|\n/)
|
|
137
|
+
.some((line) => line.trim() === _MANAGED_GITIGNORE_HEADER);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** `true` when `<start>/agents/overrides` exists as a directory. */
|
|
141
|
+
function _hasOverridesDir(start: string): boolean {
|
|
142
|
+
return _isDirAt(start, 'agents', 'overrides');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* `true` when a resolvable `.agent-settings.yml` exists — canonical
|
|
147
|
+
* `agents/settings/.agent-settings.yml`, or the legacy repo-root
|
|
148
|
+
* `.agent-settings.yml`.
|
|
149
|
+
*/
|
|
150
|
+
function _hasResolvableAgentSettings(start: string): boolean {
|
|
151
|
+
return (
|
|
152
|
+
_isFileAt(start, 'agents', 'settings', '.agent-settings.yml') ||
|
|
153
|
+
_isFileAt(start, '.agent-settings.yml')
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Classify `start` as `'managed'` (an `agents/` folder this package
|
|
159
|
+
* installed and can safely write project facts into), `'unmanaged'` (a real
|
|
160
|
+
* project — has a `.git` — with no such folder, or an `agents/` folder this
|
|
161
|
+
* package did not install), or `'not-a-project'` (no `.git` at `start` at
|
|
162
|
+
* all — e.g. a bare directory outside any repo).
|
|
163
|
+
*
|
|
164
|
+
* Read-only. Does not walk ancestors — `start` is checked directly; pass a
|
|
165
|
+
* project root (e.g. from `find_project_root`) when the caller only has a
|
|
166
|
+
* subdirectory.
|
|
167
|
+
*/
|
|
168
|
+
export function detect_managed_agents_folder(start: string): ManagedAgentsFolderStatus {
|
|
169
|
+
if (!_isGitProject(start)) {
|
|
170
|
+
return 'not-a-project';
|
|
171
|
+
}
|
|
172
|
+
const hasAgentsDir = _isDirAt(start, 'agents');
|
|
173
|
+
const hasMarker =
|
|
174
|
+
_hasManagedGitignoreBlock(start) ||
|
|
175
|
+
_hasOverridesDir(start) ||
|
|
176
|
+
_hasResolvableAgentSettings(start);
|
|
177
|
+
if (hasAgentsDir && hasMarker) {
|
|
178
|
+
return 'managed';
|
|
179
|
+
}
|
|
180
|
+
return 'unmanaged';
|
|
181
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payload-hash × cache-hit drift aggregator (pure, no-I/O).
|
|
3
|
+
*
|
|
4
|
+
* `road-to-cache-economy.md` Phase 3, step 6: the
|
|
5
|
+
* `orchestration` object's `payload_hash` and `cache_hit` fields are both
|
|
6
|
+
* `null`-by-default and read by nothing (per the roadmap's own defect list).
|
|
7
|
+
* This module is the reader: it joins the two fields recorded on the SAME
|
|
8
|
+
* audit-log-v1 line — `payload_hash` names which spawn-payload shape a
|
|
9
|
+
* dispatch used, `cache_hit` is the provider-reported prompt-cache hit for
|
|
10
|
+
* that dispatch — so prefix-stability drift becomes visible.
|
|
11
|
+
*
|
|
12
|
+
* Cohort split (the roadmap's own verify criterion — "a cohort dispatched
|
|
13
|
+
* with a deliberately unstable payload shows a lower read share than a
|
|
14
|
+
* stable one"):
|
|
15
|
+
*
|
|
16
|
+
* - STABLE cohort: every occurrence of a `payload_hash` AFTER its first —
|
|
17
|
+
* a hash that repeats means the same payload shape was dispatched again,
|
|
18
|
+
* so a cache hit on the repeat is the signal a stable prefix predicts.
|
|
19
|
+
* - UNSTABLE cohort: every `payload_hash` that occurs exactly once in the
|
|
20
|
+
* window — a payload that never repeats can never show a repeat-hit, so
|
|
21
|
+
* its (necessarily first-call) `cache_hit` value is the unstable-payload
|
|
22
|
+
* baseline.
|
|
23
|
+
*
|
|
24
|
+
* A hash's FIRST occurrence is excluded from the stable cohort — nothing
|
|
25
|
+
* exists yet for a first call to hit, so counting it would understate the
|
|
26
|
+
* stable cohort's hit rate for a reason that has nothing to do with prefix
|
|
27
|
+
* stability.
|
|
28
|
+
*
|
|
29
|
+
* Zero recorded lines is a VALID state (both fields are lean-init
|
|
30
|
+
* extensions with no caller wiring a real value yet) — the aggregator
|
|
31
|
+
* returns a report with empty cohorts rather than failing, and the CLI
|
|
32
|
+
* wrapper states that plainly rather than presenting empty input as a green
|
|
33
|
+
* result.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
export interface PayloadHashLine {
|
|
37
|
+
payload_hash: string | null;
|
|
38
|
+
cache_hit: boolean | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface HashGroupStat {
|
|
42
|
+
payload_hash: string;
|
|
43
|
+
occurrences: number;
|
|
44
|
+
hit_count: number;
|
|
45
|
+
hit_rate: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface CohortStat {
|
|
49
|
+
n: number;
|
|
50
|
+
hit_count: number;
|
|
51
|
+
hit_rate: number | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface PayloadHashDriftReport {
|
|
55
|
+
total_lines: number;
|
|
56
|
+
/** Lines carrying both a non-null `payload_hash` and a boolean `cache_hit`. */
|
|
57
|
+
lines_with_data: number;
|
|
58
|
+
/** Per-hash breakdown, most-occurrences first. */
|
|
59
|
+
groups: HashGroupStat[];
|
|
60
|
+
stable_cohort: CohortStat;
|
|
61
|
+
unstable_cohort: CohortStat;
|
|
62
|
+
/** True only when BOTH cohorts have data AND the stable cohort's hit rate is strictly higher. */
|
|
63
|
+
drift_visible: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function emptyCohort(): CohortStat {
|
|
67
|
+
return { n: 0, hit_count: 0, hit_rate: null };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Aggregates already-parsed audit-log-v1 orchestration lines. `lines` order
|
|
72
|
+
* matters — it is read as chronological (the CLI wrapper reads
|
|
73
|
+
* `agents/runtime/state/audit/*.jsonl` in filename-sorted order, matching
|
|
74
|
+
* `readAuditLines`), since "first occurrence of a hash" is the only signal
|
|
75
|
+
* that decides which cohort an occurrence falls into.
|
|
76
|
+
*/
|
|
77
|
+
export function aggregatePayloadHashDrift(lines: readonly PayloadHashLine[]): PayloadHashDriftReport {
|
|
78
|
+
const withData = lines.filter((l) => l.payload_hash !== null && l.cache_hit !== null);
|
|
79
|
+
|
|
80
|
+
const byHash = new Map<string, boolean[]>();
|
|
81
|
+
for (const l of withData) {
|
|
82
|
+
const hash = l.payload_hash as string;
|
|
83
|
+
const arr = byHash.get(hash) ?? [];
|
|
84
|
+
arr.push(l.cache_hit as boolean);
|
|
85
|
+
byHash.set(hash, arr);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const groups: HashGroupStat[] = [];
|
|
89
|
+
const stable = emptyCohort();
|
|
90
|
+
const unstable = emptyCohort();
|
|
91
|
+
|
|
92
|
+
for (const [hash, hits] of byHash) {
|
|
93
|
+
const hitCount = hits.filter(Boolean).length;
|
|
94
|
+
groups.push({
|
|
95
|
+
payload_hash: hash,
|
|
96
|
+
occurrences: hits.length,
|
|
97
|
+
hit_count: hitCount,
|
|
98
|
+
hit_rate: hitCount / hits.length,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (hits.length === 1) {
|
|
102
|
+
unstable.n += 1;
|
|
103
|
+
if (hits[0] === true) unstable.hit_count += 1;
|
|
104
|
+
} else {
|
|
105
|
+
// Every occurrence AFTER the first (repeat dispatches of the same payload shape).
|
|
106
|
+
const repeats = hits.slice(1);
|
|
107
|
+
stable.n += repeats.length;
|
|
108
|
+
stable.hit_count += repeats.filter(Boolean).length;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
groups.sort((a, b) => b.occurrences - a.occurrences || a.payload_hash.localeCompare(b.payload_hash));
|
|
113
|
+
stable.hit_rate = stable.n > 0 ? stable.hit_count / stable.n : null;
|
|
114
|
+
unstable.hit_rate = unstable.n > 0 ? unstable.hit_count / unstable.n : null;
|
|
115
|
+
|
|
116
|
+
const driftVisible = stable.hit_rate !== null && unstable.hit_rate !== null && stable.hit_rate > unstable.hit_rate;
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
total_lines: lines.length,
|
|
120
|
+
lines_with_data: withData.length,
|
|
121
|
+
groups,
|
|
122
|
+
stable_cohort: stable,
|
|
123
|
+
unstable_cohort: unstable,
|
|
124
|
+
drift_visible: driftVisible,
|
|
125
|
+
};
|
|
126
|
+
}
|