@event4u/agent-config 14.12.0 → 14.14.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +118 -155
- package/CONTRIBUTING.md +38 -0
- package/CREDITS.md +135 -0
- package/NOTICE +13 -0
- package/README.md +8 -6
- package/dist/agent-src/commands/analyze/inbox.md +145 -2
- package/dist/agent-src/commands/feature/dev.md +7 -2
- package/dist/agent-src/commands/ghostwriter/write.md +5 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/mission/upgrade.md +1 -1
- package/dist/agent-src/commands/orchestrate.md +2 -2
- package/dist/agent-src/commands/post-as/me.md +5 -1
- package/dist/agent-src/commands/pr/merge.md +19 -6
- package/dist/agent-src/commands/roadmap/process-full.md +19 -5
- package/dist/agent-src/commands/tdd/red.md +12 -2
- package/dist/agent-src/commands/work.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
- package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
- package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
- package/dist/agent-src/rules/broken-access-control.md +4 -0
- package/dist/agent-src/rules/code-comment-discipline.md +6 -0
- package/dist/agent-src/rules/code-provenance.md +4 -0
- package/dist/agent-src/rules/design-fidelity.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +4 -0
- package/dist/agent-src/rules/domain-safety-retention.md +4 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
- package/dist/agent-src/rules/improve-before-implement.md +6 -8
- package/dist/agent-src/rules/laravel-routing.md +1 -1
- package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +12 -34
- package/dist/agent-src/rules/symfony-routing.md +1 -1
- package/dist/agent-src/rules/token-efficiency.md +14 -0
- package/dist/agent-src/rules/tool-safety.md +4 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
- package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
- package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/dist/agent-src/scripts/stub_queue.ts +82 -0
- package/dist/agent-src/scripts/stubs_due.ts +516 -0
- package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
- package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
- package/dist/agent-src/skills/database/SKILL.md +8 -0
- package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
- package/dist/agent-src/skills/design-review/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
- package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
- package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
- package/dist/agent-src/skills/laravel/SKILL.md +35 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
- package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
- package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
- package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +97 -3
- package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
- package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/dist/cli/commands/uiAudit.js +124 -5
- package/dist/cli/registry.js +2 -0
- package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
- package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
- package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
- package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
- package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
- package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
- package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
- package/dist/cli-delegate/cmd_adr_effective.js +102 -0
- package/dist/cli-delegate/cmd_conformance.js +80 -11
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +3 -2
- package/dist/cli-delegate/cmd_fleet.js +2 -2
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +3 -2
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- package/dist/cli-delegate/cmd_sync.js +3 -2
- package/dist/cli-delegate/cmd_uninstall.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +3 -2
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +58 -58
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +2900 -1049
- package/dist/install/claudeRuleRewrite.js +254 -0
- package/dist/install/detect.js +29 -16
- package/dist/install/detect_php_shape.js +159 -0
- package/dist/install/install.mjs +634 -428
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +3 -3
- package/dist/mcp/server.mjs +4895 -2627
- package/dist/server/schemas/settings.js +3 -0
- package/dist/ui/assets/index-D0jaCRPM.js +29 -0
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/THIRD-PARTY-NOTICES.md +25 -0
- package/docs/contracts/provider-lifecycle.md +1 -1
- package/docs/contracts/settings-classes.md +10 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
- package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
- package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
- package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
- package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
- package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
- package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
- package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
- package/docs/guidelines/agent-infra/first-principles.md +2 -2
- package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
- package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
- package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
- package/docs/guidelines/agent-infra/layered-settings.md +10 -10
- package/docs/guidelines/agent-infra/memory-access.md +1 -1
- package/docs/guidelines/agent-infra/mental-models.md +3 -3
- package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
- package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
- package/docs/guidelines/agent-infra/role-contracts.md +2 -2
- package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
- package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
- package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
- package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
- package/docs/guidelines/agent-infra/six-hats.md +3 -3
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
- package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
- package/docs/guidelines/augment-portability-patterns.md +6 -4
- package/docs/guidelines/code-clarity.md +18 -0
- package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
- package/docs/guidelines/cross-role-handoff.md +2 -2
- package/docs/guidelines/design-fidelity-mechanics.md +1 -1
- package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
- package/docs/guidelines/php/database.md +90 -7
- package/docs/guidelines/prompt-templates.md +7 -7
- package/llms.txt +2 -2
- package/package.json +5 -2
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
- package/src/agent-src/scripts/guarded_baseline.ts +343 -0
- package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
- package/src/agent-src/scripts/stub_queue.ts +82 -0
- package/src/agent-src/scripts/stubs_due.ts +516 -0
- package/src/agent-src/scripts/ticket_bundles.ts +84 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
- package/src/agent-src/templates/scripts/check_memory.ts +258 -17
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
- package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
- package/src/config/agent-settings.template.yml +32 -3
- package/src/config/assurance-capability-registry.json +21 -9
- package/src/config/canonical-terms.yml +119 -0
- package/src/config/capability-native-outcome-bars.json +81 -0
- package/src/config/ci-local-parity.yml +80 -0
- package/src/config/drafting-channels.yml +43 -0
- package/src/config/estate-count-budget.json +57 -36
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +729 -63
- package/src/config/gate-reachability-exemptions.json +21 -0
- package/src/config/gate-violation-baselines.json +42 -19
- package/src/config/harness-evolution-budget.json +25 -0
- package/src/config/lapsed-beta-baseline.json +96 -0
- package/src/config/memory-twin-verdicts.yml +129 -0
- package/src/config/metric-registry.yml +124 -0
- package/src/config/pack-size-budget.json +16 -15
- package/src/config/preamble-payload-budget.json +12 -4
- package/src/config/profiles/balanced.ini +27 -0
- package/src/config/profiles/full.ini +27 -0
- package/src/config/profiles/minimal.ini +27 -0
- package/src/config/publish-surface.json +9 -2
- package/src/config/routing-coverage-seed.json +16 -2
- package/src/config/rule-stub-ceilings.json +133 -112
- package/src/config/turnaround-budget.json +66 -0
- package/src/install/claudeRuleRewrite.ts +288 -0
- package/src/install/detect.ts +60 -17
- package/src/install/detect_php_shape.ts +191 -0
- package/src/scripts/_cli/cmd_doctor.ts +27 -112
- package/src/scripts/_dispatch.bash +23 -0
- package/src/scripts/_lib/activation_ladder.ts +255 -0
- package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
- package/src/scripts/_lib/activation_states.ts +88 -0
- package/src/scripts/_lib/adherence_detectors.ts +143 -0
- package/src/scripts/_lib/adr_frontmatter.ts +26 -0
- package/src/scripts/_lib/arith_claims.ts +181 -0
- package/src/scripts/_lib/arm_ranking.ts +62 -0
- package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
- package/src/scripts/_lib/audit_field_provenance.ts +54 -0
- package/src/scripts/_lib/auto_dispatch.ts +32 -3
- package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
- package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
- package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
- package/src/scripts/_lib/candidate_proposer.ts +402 -0
- package/src/scripts/_lib/candidate_record.ts +601 -0
- package/src/scripts/_lib/capture_rate.ts +319 -0
- package/src/scripts/_lib/carrier_status.ts +118 -0
- package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
- package/src/scripts/_lib/collector_denominator.ts +771 -0
- package/src/scripts/_lib/collector_record.ts +340 -0
- package/src/scripts/_lib/collector_store.ts +664 -0
- package/src/scripts/_lib/collector_supervision.ts +827 -0
- package/src/scripts/_lib/concern_estate.ts +77 -0
- package/src/scripts/_lib/config_chain.ts +477 -0
- package/src/scripts/_lib/config_cost.ts +209 -0
- package/src/scripts/_lib/corpus_manifest.ts +726 -0
- package/src/scripts/_lib/council_settings_block.ts +6 -0
- package/src/scripts/_lib/curator_ops.ts +172 -0
- package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
- package/src/scripts/_lib/delivery_criticality.ts +126 -0
- package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
- package/src/scripts/_lib/empty_cycles.ts +88 -0
- package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
- package/src/scripts/_lib/eval_publication.ts +354 -0
- package/src/scripts/_lib/evaluation_cascade.ts +452 -0
- package/src/scripts/_lib/evaluation_vector.ts +283 -0
- package/src/scripts/_lib/evaluator_promotion.ts +225 -0
- package/src/scripts/_lib/evidence_basis.ts +118 -0
- package/src/scripts/_lib/evolution_roi.ts +562 -0
- package/src/scripts/_lib/exec_evidence.ts +8 -0
- package/src/scripts/_lib/experience_card.ts +272 -0
- package/src/scripts/_lib/experience_report.ts +151 -0
- package/src/scripts/_lib/experiment_freeze.ts +112 -0
- package/src/scripts/_lib/generated_by.ts +66 -0
- package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
- package/src/scripts/_lib/hook_effect_probe.ts +141 -0
- package/src/scripts/_lib/host_denominator.ts +687 -0
- package/src/scripts/_lib/host_projection_reach.ts +157 -0
- package/src/scripts/_lib/ignored_blocker.ts +148 -0
- package/src/scripts/_lib/install_reach_checks.ts +495 -0
- package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
- package/src/scripts/_lib/judge_hygiene.ts +228 -0
- package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
- package/src/scripts/_lib/lexical_shortlist.ts +215 -0
- package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
- package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
- package/src/scripts/_lib/loop_guards.ts +299 -0
- package/src/scripts/_lib/loss_class.ts +129 -0
- package/src/scripts/_lib/machine_wake.ts +51 -0
- package/src/scripts/_lib/md_prose_lines.ts +177 -0
- package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
- package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
- package/src/scripts/_lib/orchestration_record.ts +253 -5
- package/src/scripts/_lib/outcome_envelope.ts +227 -0
- package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
- package/src/scripts/_lib/paired_stats.ts +245 -0
- package/src/scripts/_lib/paired_verdict.ts +226 -0
- package/src/scripts/_lib/pathology_archive.ts +393 -0
- package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
- package/src/scripts/_lib/privacy_class.ts +47 -0
- package/src/scripts/_lib/promotion_capability.ts +315 -0
- package/src/scripts/_lib/promotion_evidence.ts +414 -0
- package/src/scripts/_lib/promotion_review.ts +294 -0
- package/src/scripts/_lib/prompt_shape.ts +92 -0
- package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
- package/src/scripts/_lib/release_highlights.ts +70 -1
- package/src/scripts/_lib/release_material.ts +125 -2
- package/src/scripts/_lib/repeated_failure.ts +105 -0
- package/src/scripts/_lib/repo_root.ts +111 -0
- package/src/scripts/_lib/review_skipped_record.ts +37 -0
- package/src/scripts/_lib/role_split.ts +338 -0
- package/src/scripts/_lib/routing_corpus.ts +307 -0
- package/src/scripts/_lib/routing_index_input.ts +104 -0
- package/src/scripts/_lib/rule_injection.ts +22 -1
- package/src/scripts/_lib/runtime_journal.ts +1499 -0
- package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
- package/src/scripts/_lib/semantic_noop.ts +167 -0
- package/src/scripts/_lib/skill_catalogue.ts +11 -1
- package/src/scripts/_lib/source_digest.ts +200 -0
- package/src/scripts/_lib/source_redact.ts +260 -0
- package/src/scripts/_lib/source_shape.ts +502 -0
- package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
- package/src/scripts/_lib/strip_comments.d.mts +8 -0
- package/src/scripts/_lib/strip_comments.mjs +65 -0
- package/src/scripts/_lib/test_red_state.ts +154 -0
- package/src/scripts/_lib/trigger_shift.ts +144 -0
- package/src/scripts/_lib/untrusted_content.ts +82 -7
- package/src/scripts/activation_receipt.ts +258 -0
- package/src/scripts/adoption_report.ts +1 -1
- package/src/scripts/adr/evidence_census.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +26 -2
- package/src/scripts/adr_cite_check.ts +164 -1
- package/src/scripts/ai_council/blind_review.ts +11 -1
- package/src/scripts/ai_council/clients.ts +4 -0
- package/src/scripts/ai_council/config.ts +3 -0
- package/src/scripts/ai_council/consensus.ts +28 -8
- package/src/scripts/ai_council/consensus_round.ts +226 -0
- package/src/scripts/ai_council/cross_exam.ts +128 -0
- package/src/scripts/ai_council/disagreement_signal.ts +338 -0
- package/src/scripts/ai_council/explain_route.ts +157 -0
- package/src/scripts/ai_council/information_gain.ts +293 -0
- package/src/scripts/ai_council/inline_findings.ts +340 -0
- package/src/scripts/ai_council/judge_position_bias.ts +197 -0
- package/src/scripts/ai_council/leakage_corpus.ts +385 -0
- package/src/scripts/ai_council/leakage_patterns.ts +453 -0
- package/src/scripts/ai_council/minority_retention.ts +171 -0
- package/src/scripts/ai_council/orchestrator.ts +16 -203
- package/src/scripts/ai_council/orchestrator_results.ts +23 -3
- package/src/scripts/ai_council/pricing.ts +106 -0
- package/src/scripts/ai_council/prompts.ts +74 -7
- package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
- package/src/scripts/ai_council/py_format.ts +14 -3
- package/src/scripts/ai_council/recouncil_guard.ts +293 -0
- package/src/scripts/ai_council/recouncil_savings.ts +299 -0
- package/src/scripts/ai_council/replay_route.ts +223 -0
- package/src/scripts/ai_council/response_record.ts +50 -0
- package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
- package/src/scripts/ai_council/routing_training_row.ts +197 -0
- package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
- package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
- package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
- package/src/scripts/asset_delivery_ledger.ts +157 -0
- package/src/scripts/attest_artifact.ts +193 -0
- package/src/scripts/audit_auto_rules.ts +2 -1
- package/src/scripts/audit_command_surface.ts +1 -1
- package/src/scripts/audit_mcp_tools.ts +2 -2
- package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
- package/src/scripts/audit_user_type_axis.ts +2 -1
- package/src/scripts/bench_ab_clone.ts +215 -10
- package/src/scripts/bench_ab_integrity.ts +119 -5
- package/src/scripts/bench_ab_v2_stats.ts +40 -213
- package/src/scripts/build_archive_index.ts +1 -1
- package/src/scripts/build_linear_digest.ts +1 -1
- package/src/scripts/build_proof.ts +11 -4
- package/src/scripts/build_rule_trigger_matrix.ts +1 -1
- package/src/scripts/build_source_digests.ts +157 -0
- package/src/scripts/cache_realization_report.ts +103 -0
- package/src/scripts/check_adr_frontmatter.ts +131 -10
- package/src/scripts/check_benchmark_report_fields.ts +207 -0
- package/src/scripts/check_beta_review_markers.ts +235 -6
- package/src/scripts/check_bundle_path_leakage.ts +34 -1
- package/src/scripts/check_claims.ts +576 -6
- package/src/scripts/check_composite_arming.ts +35 -0
- package/src/scripts/check_concern_admissions.ts +365 -0
- package/src/scripts/check_enforcement_coverage.ts +28 -0
- package/src/scripts/check_estate_count.ts +347 -25
- package/src/scripts/check_gate_reachability.ts +383 -0
- package/src/scripts/check_host_loadability.ts +104 -0
- package/src/scripts/check_loss_class_declared.ts +308 -0
- package/src/scripts/check_md_language.ts +15 -98
- package/src/scripts/check_memory_proposal.ts +18 -11
- package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
- package/src/scripts/check_no_external_sources.ts +281 -6
- package/src/scripts/check_pack_conformance_fixture.ts +11 -1
- package/src/scripts/check_pack_size.ts +59 -2
- package/src/scripts/check_preamble_payload_budget.ts +114 -3
- package/src/scripts/check_prefix_stable_mutation.ts +372 -0
- package/src/scripts/check_publish_surface.ts +10 -1
- package/src/scripts/check_references.ts +24 -1
- package/src/scripts/check_release_highlights.ts +96 -13
- package/src/scripts/check_roadmap_trackable.ts +17 -2
- package/src/scripts/check_rule_evidence_declaration.ts +316 -0
- package/src/scripts/check_rule_projection_integrity.ts +14 -4
- package/src/scripts/check_score_contract.ts +26 -3
- package/src/scripts/check_static_parity.ts +285 -0
- package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
- package/src/scripts/check_suppression_hygiene.ts +15 -0
- package/src/scripts/ci_settle.ts +39 -2
- package/src/scripts/code_graph/build.ts +60 -3
- package/src/scripts/code_graph/extract.ts +44 -0
- package/src/scripts/code_graph/types.ts +24 -0
- package/src/scripts/collector_daemon.ts +714 -0
- package/src/scripts/config_cost_report.ts +302 -0
- package/src/scripts/consumer_matrix.ts +74 -1
- package/src/scripts/corpus_manifest.ts +235 -0
- package/src/scripts/cost/budget.mjs +10 -3
- package/src/scripts/cost/track.mjs +10 -3
- package/src/scripts/council_cli.ts +37 -54
- package/src/scripts/dispatch_r2_reviewer.ts +46 -5
- package/src/scripts/evolution_lab.ts +1153 -0
- package/src/scripts/external_sources_denylist.json +5 -18
- package/src/scripts/extract_audit_patterns.ts +21 -0
- package/src/scripts/fold_intake.ts +12 -1
- package/src/scripts/gen_discovery_baseline.ts +1 -1
- package/src/scripts/generate_capabilities_index.ts +12 -5
- package/src/scripts/generate_capability_matrix.ts +3 -3
- package/src/scripts/generate_command_flows.ts +2 -2
- package/src/scripts/generate_cookbook.ts +2 -2
- package/src/scripts/generate_index.ts +8 -1
- package/src/scripts/generate_knowledge_index.ts +2 -1
- package/src/scripts/generate_ownership_matrix.ts +2 -1
- package/src/scripts/generate_pack_manifests.ts +10 -2
- package/src/scripts/generate_role_experiences_catalog.ts +2 -2
- package/src/scripts/generate_settings_reference.ts +1 -1
- package/src/scripts/git_authorization_hook.ts +22 -1
- package/src/scripts/grade_target_readiness.ts +48 -5
- package/src/scripts/hook_effect_doctor.ts +261 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +125 -16
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
- package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
- package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
- package/src/scripts/hooks/concern_registry.ts +6 -0
- package/src/scripts/hooks/dispatch_hook.ts +32 -0
- package/src/scripts/hooks/journal_record_hook.ts +345 -0
- package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
- package/src/scripts/hooks/run_continuation_hook.ts +44 -9
- package/src/scripts/hooks/shims/install.sh +61 -0
- package/src/scripts/hooks/shims/php +101 -0
- package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
- package/src/scripts/hot_context_hook.ts +16 -0
- package/src/scripts/install-hooks.sh +20 -5
- package/src/scripts/install.ts +17 -35
- package/src/scripts/inventory_frontmatter.ts +2 -1
- package/src/scripts/language_mirror_hook.ts +14 -2
- package/src/scripts/lint_adr_sweep_routing.ts +12 -0
- package/src/scripts/lint_canonical_terms.ts +604 -0
- package/src/scripts/lint_carrier_integrity.ts +820 -0
- package/src/scripts/lint_code_comments.ts +643 -0
- package/src/scripts/lint_composition_review.ts +619 -0
- package/src/scripts/lint_consolidation_lineage.ts +666 -0
- package/src/scripts/lint_eval_specs.ts +593 -0
- package/src/scripts/lint_hook_manifest.ts +19 -0
- package/src/scripts/lint_host_portability.ts +373 -0
- package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
- package/src/scripts/lint_memory_twin_parity.ts +335 -0
- package/src/scripts/lint_metric_consumers.ts +355 -0
- package/src/scripts/lint_plan_risk_register.ts +39 -19
- package/src/scripts/lint_promotion_paths.ts +779 -0
- package/src/scripts/lint_skill_descriptions.ts +18 -1
- package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
- package/src/scripts/lint_skill_link_reach.ts +252 -0
- package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
- package/src/scripts/lint_ticket_buildable.ts +17 -1
- package/src/scripts/llm_propose.ts +256 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
- package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
- package/src/scripts/measure_delivery_sets.ts +361 -0
- package/src/scripts/measure_docs_dead_links.ts +348 -0
- package/src/scripts/measure_host_capture.ts +461 -0
- package/src/scripts/measure_routing_signal.ts +307 -0
- package/src/scripts/migration_status.ts +3 -3
- package/src/scripts/model_rule_injection.ts +76 -0
- package/src/scripts/orchestration_record.ts +14 -0
- package/src/scripts/preamble_byte_census.ts +139 -10
- package/src/scripts/prepack-check.mjs +4 -1
- package/src/scripts/probe_council_retention.ts +495 -0
- package/src/scripts/probe_turnaround.ts +384 -0
- package/src/scripts/probe_unblocked_ask.ts +279 -0
- package/src/scripts/release.ts +21 -37
- package/src/scripts/release_drill.ts +143 -0
- package/src/scripts/release_env.ts +35 -0
- package/src/scripts/release_publication.ts +84 -0
- package/src/scripts/render_benchmark_md.ts +1 -1
- package/src/scripts/rule_activation_census.ts +70 -9
- package/src/scripts/rule_backlinks.ts +1 -1
- package/src/scripts/run_lifecycle_suite.ts +208 -0
- package/src/scripts/run_skill_evals.ts +40 -0
- package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
- package/src/scripts/schemas/drafting-channels.schema.json +43 -0
- package/src/scripts/schemas/evals.schema.json +24 -1
- package/src/scripts/schemas/rule.schema.json +52 -1
- package/src/scripts/schemas/skill.schema.json +17 -2
- package/src/scripts/skill_overlap.ts +7 -1
- package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
- package/src/scripts/skill_usage_report.ts +2 -1
- package/src/scripts/stubs_due.ts +211 -0
- package/src/scripts/sweep_source_surfaces.ts +678 -0
- package/src/scripts/sync_pr_branch.ts +3 -3
- package/src/scripts/trigger_eval_grandfather.json +202 -222
- package/src/scripts/utilization_report.ts +22 -2
- package/src/server/schemas/settings.ts +5 -0
- package/src/templates/marketing-copy.yml +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +0 -26
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Count hook concerns in `src/scripts/hook_manifest.yaml`.
|
|
3
|
+
*
|
|
4
|
+
* ONE parser, used for both the HEAD reading and the base-ref floor — the same
|
|
5
|
+
* discipline `_lib/skill_estate.ts` follows for skills, and for the same
|
|
6
|
+
* reason: two readings of one corpus is how a ratchet comes to compare a
|
|
7
|
+
* number against a differently-derived number and calls the difference growth.
|
|
8
|
+
*
|
|
9
|
+
* ## Why this is not the roadmap's grep
|
|
10
|
+
*
|
|
11
|
+
* `road-to-concern-admission-ratchet` reproduces its series with
|
|
12
|
+
* `grep -cE '^ [a-z][a-z0-9_-]*:$'` over the whole manifest. That command is a
|
|
13
|
+
* PROXY and it over-counts: the manifest carries three further top-level maps —
|
|
14
|
+
* `roles:`, `platforms:` and `native_event_aliases:` — whose members sit at the
|
|
15
|
+
* same two-space indent and match the same pattern.
|
|
16
|
+
*
|
|
17
|
+
* Measured across the roadmap's own six pins, the over-count is **exactly 16 at
|
|
18
|
+
* every one of them**:
|
|
19
|
+
*
|
|
20
|
+
* | pin | grep | concerns |
|
|
21
|
+
* |---|---|---|
|
|
22
|
+
* | `7c6a71d` | 63 | 47 |
|
|
23
|
+
* | `1dba34c8` | 65 | 49 |
|
|
24
|
+
* | `40791536` | 65 | 49 |
|
|
25
|
+
* | `0f7c26ee9` | 68 | 52 |
|
|
26
|
+
* | `2bcefb8b1` | 69 | 53 |
|
|
27
|
+
* | `6e37584a1` | 71 | 55 |
|
|
28
|
+
*
|
|
29
|
+
* Two consequences, and they point in opposite directions, so both are stated.
|
|
30
|
+
* **The roadmap's FINDING survives untouched**: the delta is constant, so the
|
|
31
|
+
* series climbs by +8 either way and the concern axis is growing exactly as it
|
|
32
|
+
* says. **Its ABSOLUTE FIGURES do not**: the axis stands at 55, not 71. A
|
|
33
|
+
* ratchet seeded with 71 would have a floor its own parser could never
|
|
34
|
+
* reproduce, which is a gate that fails on its first honest run.
|
|
35
|
+
*
|
|
36
|
+
* This module is therefore scoped to the `concerns:` block and stops at the
|
|
37
|
+
* next top-level key.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/** A top-level YAML key at column 0 — where the `concerns:` block ends. */
|
|
41
|
+
const TOP_LEVEL_KEY = /^[A-Za-z_][A-Za-z0-9_-]*:/;
|
|
42
|
+
/** The `concerns:` map itself. */
|
|
43
|
+
const CONCERNS_KEY = /^concerns:\s*$/;
|
|
44
|
+
/**
|
|
45
|
+
* One concern id: two-space indent, a bare key, nothing after the colon.
|
|
46
|
+
*
|
|
47
|
+
* A trailing value (`foo: bar`) is not a concern — concerns are maps. Matching
|
|
48
|
+
* the bare form is what keeps a scalar setting inside the block from counting.
|
|
49
|
+
*/
|
|
50
|
+
const CONCERN_ID = /^ {2}([a-z][a-z0-9_-]*):\s*$/;
|
|
51
|
+
|
|
52
|
+
/** The ids, in file order. Exported so a caller can report WHICH, not only how many. */
|
|
53
|
+
export function concernIds(manifestText: string): string[] {
|
|
54
|
+
const out: string[] = [];
|
|
55
|
+
let inBlock = false;
|
|
56
|
+
for (const line of manifestText.split('\n')) {
|
|
57
|
+
if (CONCERNS_KEY.test(line)) {
|
|
58
|
+
inBlock = true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (!inBlock) continue;
|
|
62
|
+
// Any other column-0 key closes the block. Checked BEFORE the id match
|
|
63
|
+
// so a top-level key can never be read as a concern.
|
|
64
|
+
if (TOP_LEVEL_KEY.test(line)) break;
|
|
65
|
+
const m = CONCERN_ID.exec(line);
|
|
66
|
+
if (m !== null) out.push(m[1] as string);
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** How many concerns the manifest declares. */
|
|
72
|
+
export function countConcerns(manifestText: string): number {
|
|
73
|
+
return concernIds(manifestText).length;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Repo-relative POSIX path of the manifest, for both the HEAD read and the `git show`. */
|
|
77
|
+
export const CONCERN_MANIFEST_POSIX = 'src/scripts/hook_manifest.yaml';
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a configuration file's `extends` / `includes` chain, and answer which
|
|
3
|
+
* config governs a given path, before anything digests either one.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS
|
|
6
|
+
* ---------------
|
|
7
|
+
* `standards-from-config` derives a project's enforced standards from its real
|
|
8
|
+
* tooling config. Read literally — one file, one parse — that produces a null on
|
|
9
|
+
* a repository whose root config is a single directive pointing somewhere else.
|
|
10
|
+
* A fourteen-line linter config whose only load-bearing line is an `extends` into
|
|
11
|
+
* a package in the same workspace is not a project without standards; it is a
|
|
12
|
+
* project whose standards are one hop away. Reporting "no enforced standard
|
|
13
|
+
* found" there is a false negative that reads exactly like a true one.
|
|
14
|
+
*
|
|
15
|
+
* `extends` is a specified directive in TypeScript, ESLint, Biome and Stylelint;
|
|
16
|
+
* `includes` plays the same role in PHPStan's NEON. `workspace:`-linked packages
|
|
17
|
+
* are a documented protocol in npm, yarn, pnpm and bun. Those are published
|
|
18
|
+
* mechanisms, which is why chain-following is a general capability rather than
|
|
19
|
+
* one repository's convention.
|
|
20
|
+
*
|
|
21
|
+
* AN EXTERNAL HOP IS LABELLED, NEVER MERGED
|
|
22
|
+
* -----------------------------------------
|
|
23
|
+
* A chain can leave the repository — into `node_modules`, into a vendor
|
|
24
|
+
* directory, or above the repository root entirely. Presenting a third-party
|
|
25
|
+
* preset as *the project's own* standard is worse than reporting nothing: the
|
|
26
|
+
* reader cannot tell which rules the project chose. So every hop carries its
|
|
27
|
+
* origin, and only `project` and `workspace-package` hops appear in
|
|
28
|
+
* `digestible`. An `external` hop is reported, with its path, and excluded from
|
|
29
|
+
* the digest.
|
|
30
|
+
*
|
|
31
|
+
* AN UNRESOLVABLE HOP IS A NAMED GAP, NEVER AN ABSENCE
|
|
32
|
+
* ---------------------------------------------------
|
|
33
|
+
* Three failures are indistinguishable to a caller that only sees "nothing came
|
|
34
|
+
* back": the file is missing, the file is there but unparsable, and the
|
|
35
|
+
* directive is expressed in a language this reader does not evaluate (a Rector
|
|
36
|
+
* config building its set list from PHP expressions). All three are recorded as
|
|
37
|
+
* a hop with `origin: 'unresolved'` and a `reason`, and any one of them sets
|
|
38
|
+
* `complete: false`. A partial digest that says which hop it could not follow is
|
|
39
|
+
* usable; a null is not, and a null that looks like "no standards" is a lie.
|
|
40
|
+
* This is the same three-outcome posture the install diagnostic takes: present,
|
|
41
|
+
* dangling, and unresolvable-for-a-stated-reason — never a silent absence.
|
|
42
|
+
*
|
|
43
|
+
* WHY A LOCAL JSONC READER
|
|
44
|
+
* ------------------------
|
|
45
|
+
* `linked_projects.ts` carries a private tolerant JSON reader that returns
|
|
46
|
+
* `null` on both "absent" and "malformed". That collapse is correct for its
|
|
47
|
+
* input domain and wrong here for the reason above: this module has to attribute
|
|
48
|
+
* a parse failure to itself rather than report it as a missing config. So
|
|
49
|
+
* `readConfigObject` returns a discriminated result instead of a nullable one.
|
|
50
|
+
*/
|
|
51
|
+
import * as fs from 'node:fs';
|
|
52
|
+
import * as path from 'node:path';
|
|
53
|
+
import * as yaml from 'yaml';
|
|
54
|
+
|
|
55
|
+
/** Where a hop's file lives relative to the repository — the digest gate. */
|
|
56
|
+
export type HopOrigin = 'project' | 'workspace-package' | 'external' | 'unresolved';
|
|
57
|
+
|
|
58
|
+
export interface ConfigHop {
|
|
59
|
+
/** The directive text as written. `''` for the chain's starting file. */
|
|
60
|
+
specifier: string;
|
|
61
|
+
/** Repository-relative path when resolved, `null` when not. */
|
|
62
|
+
path: string | null;
|
|
63
|
+
origin: HopOrigin;
|
|
64
|
+
/**
|
|
65
|
+
* Present on every non-`project` hop. On `unresolved` it names WHY, which is
|
|
66
|
+
* the whole point — an unnamed gap is an absence wearing a label.
|
|
67
|
+
*/
|
|
68
|
+
reason?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ChainResolution {
|
|
72
|
+
/** Every hop, in resolution order, starting with the file asked about. */
|
|
73
|
+
hops: ConfigHop[];
|
|
74
|
+
/** `false` when any hop is `unresolved`. A partial digest, never a null. */
|
|
75
|
+
complete: boolean;
|
|
76
|
+
/** The hops a digest may read: `project` + `workspace-package` only. */
|
|
77
|
+
digestible: ConfigHop[];
|
|
78
|
+
/** Hops outside the repository. Reported, never merged into the digest. */
|
|
79
|
+
externals: ConfigHop[];
|
|
80
|
+
/** The named gaps. Non-empty exactly when `complete` is `false`. */
|
|
81
|
+
unresolved: ConfigHop[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface WorkspacePackage {
|
|
85
|
+
/** Repository-relative directory. */
|
|
86
|
+
dir: string;
|
|
87
|
+
/** The manifest's `name` — the key a bare specifier matches on. */
|
|
88
|
+
name: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Bounds the walk. A chain this long is a finding, not a configuration. */
|
|
92
|
+
const MAX_HOPS = 16;
|
|
93
|
+
|
|
94
|
+
/** Directory names a chain crosses only to leave the repository. */
|
|
95
|
+
const EXTERNAL_DIRS = new Set(['node_modules', 'vendor']);
|
|
96
|
+
|
|
97
|
+
/** Extensions tried when a specifier names no file extension of its own. */
|
|
98
|
+
const EXT_CANDIDATES = ['', '.json', '.jsonc', '.neon', '.yaml', '.yml'];
|
|
99
|
+
|
|
100
|
+
/** Filenames tried when a specifier resolves to a directory. */
|
|
101
|
+
const DIR_CANDIDATES = [
|
|
102
|
+
'tsconfig.json',
|
|
103
|
+
'biome.json',
|
|
104
|
+
'eslint.config.js',
|
|
105
|
+
'.eslintrc.json',
|
|
106
|
+
'.stylelintrc.json',
|
|
107
|
+
'phpstan.neon',
|
|
108
|
+
'index.json',
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
type ReadResult =
|
|
112
|
+
| { kind: 'ok'; value: Record<string, unknown> }
|
|
113
|
+
| { kind: 'absent' }
|
|
114
|
+
| { kind: 'unparsable'; reason: string }
|
|
115
|
+
| { kind: 'opaque'; reason: string };
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Read one config file into an object, keeping the four outcomes distinct.
|
|
119
|
+
*
|
|
120
|
+
* `opaque` is the case a null would hide: a `.php` config states its directives
|
|
121
|
+
* as executable expressions, so a static reader cannot follow them and must say
|
|
122
|
+
* so rather than report the file as carrying none.
|
|
123
|
+
*/
|
|
124
|
+
export function readConfigObject(absPath: string): ReadResult {
|
|
125
|
+
if (!fs.existsSync(absPath)) return { kind: 'absent' };
|
|
126
|
+
const ext = path.extname(absPath).toLowerCase();
|
|
127
|
+
if (ext === '.php' || ext === '.js' || ext === '.cjs' || ext === '.mjs' || ext === '.ts') {
|
|
128
|
+
return {
|
|
129
|
+
kind: 'opaque',
|
|
130
|
+
reason: `${ext} config: directives are expressed as executable code and are not statically resolvable`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
let text: string;
|
|
134
|
+
try {
|
|
135
|
+
text = fs.readFileSync(absPath, 'utf-8');
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return { kind: 'unparsable', reason: `unreadable: ${(err as Error).message}` };
|
|
138
|
+
}
|
|
139
|
+
if (ext === '.neon' || ext === '.yaml' || ext === '.yml') {
|
|
140
|
+
// NEON's `includes:` list and YAML's `extends:` are both a top-level key
|
|
141
|
+
// holding a scalar or a sequence, which YAML parses for both formats.
|
|
142
|
+
try {
|
|
143
|
+
const parsed = yaml.parse(text) as unknown;
|
|
144
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
145
|
+
return { kind: 'unparsable', reason: 'top level is not a mapping' };
|
|
146
|
+
}
|
|
147
|
+
return { kind: 'ok', value: parsed as Record<string, unknown> };
|
|
148
|
+
} catch (err) {
|
|
149
|
+
return { kind: 'unparsable', reason: `parse error: ${(err as Error).message}` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const strict = tryJson(text);
|
|
153
|
+
if (strict) return { kind: 'ok', value: strict };
|
|
154
|
+
// tsconfig.json and its family carry `//` comments and trailing commas by
|
|
155
|
+
// convention, so a strict parse failure is not yet a finding.
|
|
156
|
+
const tolerant = tryJson(text.replace(/^\s*\/\/.*$/gm, '').replace(/,(\s*[}\]])/g, '$1'));
|
|
157
|
+
if (tolerant) return { kind: 'ok', value: tolerant };
|
|
158
|
+
return { kind: 'unparsable', reason: 'not valid JSON, even allowing comments and trailing commas' };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function tryJson(text: string): Record<string, unknown> | null {
|
|
162
|
+
try {
|
|
163
|
+
const parsed = JSON.parse(text) as unknown;
|
|
164
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
|
|
165
|
+
return parsed as Record<string, unknown>;
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Pull the chain directives out of a parsed config, in declaration order. */
|
|
172
|
+
function directives(config: Record<string, unknown>): string[] {
|
|
173
|
+
const out: string[] = [];
|
|
174
|
+
for (const key of ['extends', 'includes']) {
|
|
175
|
+
const raw = config[key];
|
|
176
|
+
if (typeof raw === 'string') out.push(raw);
|
|
177
|
+
else if (Array.isArray(raw)) {
|
|
178
|
+
for (const item of raw) if (typeof item === 'string') out.push(item);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Enumerate the repository's workspace packages from its declarative source.
|
|
186
|
+
*
|
|
187
|
+
* `pnpm-workspace.yaml` wins when present because it is the more specific
|
|
188
|
+
* declaration; otherwise `package.json#workspaces`. Conventional directories are
|
|
189
|
+
* never used as a substitute — a declaration and a convention can disagree, and
|
|
190
|
+
* the declaration is what the package manager obeys.
|
|
191
|
+
*/
|
|
192
|
+
export function listWorkspacePackages(repoRoot: string): WorkspacePackage[] {
|
|
193
|
+
const patterns = workspacePatterns(repoRoot);
|
|
194
|
+
const seen = new Set<string>();
|
|
195
|
+
const out: WorkspacePackage[] = [];
|
|
196
|
+
for (const pattern of patterns) {
|
|
197
|
+
for (const dir of expandPattern(repoRoot, pattern)) {
|
|
198
|
+
if (seen.has(dir)) continue;
|
|
199
|
+
seen.add(dir);
|
|
200
|
+
const manifest = readConfigObject(path.join(repoRoot, dir, 'package.json'));
|
|
201
|
+
if (manifest.kind !== 'ok') continue;
|
|
202
|
+
const name = manifest.value.name;
|
|
203
|
+
if (typeof name === 'string' && name.length > 0) out.push({ dir, name });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function workspacePatterns(repoRoot: string): string[] {
|
|
210
|
+
const pnpm = path.join(repoRoot, 'pnpm-workspace.yaml');
|
|
211
|
+
if (fs.existsSync(pnpm)) {
|
|
212
|
+
const parsed = readConfigObject(pnpm);
|
|
213
|
+
if (parsed.kind === 'ok' && Array.isArray(parsed.value.packages)) {
|
|
214
|
+
return (parsed.value.packages as unknown[]).filter((p): p is string => typeof p === 'string');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const rootManifest = readConfigObject(path.join(repoRoot, 'package.json'));
|
|
218
|
+
if (rootManifest.kind === 'ok') {
|
|
219
|
+
const ws = rootManifest.value.workspaces;
|
|
220
|
+
if (Array.isArray(ws)) return ws.filter((p): p is string => typeof p === 'string');
|
|
221
|
+
if (ws && typeof ws === 'object' && Array.isArray((ws as Record<string, unknown>).packages)) {
|
|
222
|
+
return ((ws as Record<string, unknown>).packages as unknown[]).filter(
|
|
223
|
+
(p): p is string => typeof p === 'string',
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Expand one workspace glob to the directories that actually carry a manifest.
|
|
232
|
+
*
|
|
233
|
+
* Only `*` and `**` as whole path segments are supported, which is what every
|
|
234
|
+
* workspace declaration in the wild uses. A pattern this cannot express returns
|
|
235
|
+
* nothing rather than a guess — a wrong workspace list would misclassify an
|
|
236
|
+
* external hop as the project's own, which is the one error this module exists
|
|
237
|
+
* to prevent.
|
|
238
|
+
*/
|
|
239
|
+
function expandPattern(repoRoot: string, pattern: string): string[] {
|
|
240
|
+
const segments = pattern.replace(/^\.\//, '').split('/').filter((s) => s.length > 0);
|
|
241
|
+
let frontier: string[] = [''];
|
|
242
|
+
for (const segment of segments) {
|
|
243
|
+
const next: string[] = [];
|
|
244
|
+
for (const base of frontier) {
|
|
245
|
+
if (segment === '*') next.push(...childDirs(repoRoot, base));
|
|
246
|
+
else if (segment === '**') next.push(base, ...recursiveDirs(repoRoot, base, 4));
|
|
247
|
+
else {
|
|
248
|
+
const candidate = base ? `${base}/${segment}` : segment;
|
|
249
|
+
if (isDir(path.join(repoRoot, candidate))) next.push(candidate);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
frontier = next;
|
|
253
|
+
}
|
|
254
|
+
return frontier.filter((d) => d.length > 0);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function childDirs(repoRoot: string, base: string): string[] {
|
|
258
|
+
const abs = path.join(repoRoot, base);
|
|
259
|
+
if (!isDir(abs)) return [];
|
|
260
|
+
return fs
|
|
261
|
+
.readdirSync(abs, { withFileTypes: true })
|
|
262
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith('.') && !EXTERNAL_DIRS.has(e.name))
|
|
263
|
+
.map((e) => (base ? `${base}/${e.name}` : e.name));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function recursiveDirs(repoRoot: string, base: string, depth: number): string[] {
|
|
267
|
+
if (depth <= 0) return [];
|
|
268
|
+
const out: string[] = [];
|
|
269
|
+
for (const child of childDirs(repoRoot, base)) {
|
|
270
|
+
out.push(child, ...recursiveDirs(repoRoot, child, depth - 1));
|
|
271
|
+
}
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function isDir(abs: string): boolean {
|
|
276
|
+
try {
|
|
277
|
+
return fs.statSync(abs).isDirectory();
|
|
278
|
+
} catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Classify a resolved absolute path by where it sits relative to the repo. */
|
|
284
|
+
function classify(repoRoot: string, abs: string): { origin: HopOrigin; reason?: string } {
|
|
285
|
+
const rel = path.relative(repoRoot, abs);
|
|
286
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
287
|
+
return { origin: 'external', reason: 'resolves above the repository root' };
|
|
288
|
+
}
|
|
289
|
+
const crossed = rel.split(path.sep).find((seg) => EXTERNAL_DIRS.has(seg));
|
|
290
|
+
if (crossed) return { origin: 'external', reason: `resolves inside \`${crossed}/\`` };
|
|
291
|
+
return { origin: 'project' };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Try a specifier as a file, then with each extension, then as a directory. */
|
|
295
|
+
function firstExistingFile(base: string): string | null {
|
|
296
|
+
for (const ext of EXT_CANDIDATES) {
|
|
297
|
+
const candidate = base + ext;
|
|
298
|
+
if (fs.existsSync(candidate) && !isDir(candidate)) return candidate;
|
|
299
|
+
}
|
|
300
|
+
if (isDir(base)) {
|
|
301
|
+
for (const name of DIR_CANDIDATES) {
|
|
302
|
+
const candidate = path.join(base, name);
|
|
303
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function resolveSpecifier(
|
|
310
|
+
repoRoot: string,
|
|
311
|
+
fromDir: string,
|
|
312
|
+
specifier: string,
|
|
313
|
+
workspaces: WorkspacePackage[],
|
|
314
|
+
): ConfigHop {
|
|
315
|
+
const hop = (patch: Partial<ConfigHop>): ConfigHop => ({ specifier, path: null, origin: 'unresolved', ...patch });
|
|
316
|
+
|
|
317
|
+
if (specifier.startsWith('.') || path.isAbsolute(specifier)) {
|
|
318
|
+
const base = path.isAbsolute(specifier) ? specifier : path.resolve(fromDir, specifier);
|
|
319
|
+
const found = firstExistingFile(base);
|
|
320
|
+
if (!found) return hop({ reason: 'relative target does not exist' });
|
|
321
|
+
const { origin, reason } = classify(repoRoot, found);
|
|
322
|
+
return hop({ path: path.relative(repoRoot, found), origin, ...(reason === undefined ? {} : { reason }) });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// A bare specifier is a workspace package before it is a dependency: a
|
|
326
|
+
// `workspace:`-linked config package is INSIDE the repository, so its rules
|
|
327
|
+
// are the project's own and belong in the digest.
|
|
328
|
+
const match = workspaces
|
|
329
|
+
.filter((ws) => specifier === ws.name || specifier.startsWith(`${ws.name}/`))
|
|
330
|
+
.sort((a, b) => b.name.length - a.name.length)[0];
|
|
331
|
+
if (match) {
|
|
332
|
+
const subpath = specifier.slice(match.name.length).replace(/^\//, '');
|
|
333
|
+
const wsDir = path.join(repoRoot, match.dir);
|
|
334
|
+
const found = subpath ? firstExistingFile(path.join(wsDir, subpath)) : workspaceEntry(wsDir);
|
|
335
|
+
if (!found) {
|
|
336
|
+
return hop({ reason: `workspace package \`${match.name}\` has no config at \`${subpath || 'its entry point'}\`` });
|
|
337
|
+
}
|
|
338
|
+
return hop({ path: path.relative(repoRoot, found), origin: 'workspace-package', reason: `workspace package \`${match.name}\`` });
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const installed = firstExistingFile(path.join(repoRoot, 'node_modules', specifier));
|
|
342
|
+
if (installed) {
|
|
343
|
+
return hop({ path: path.relative(repoRoot, installed), origin: 'external', reason: 'resolves inside `node_modules/`' });
|
|
344
|
+
}
|
|
345
|
+
return hop({ reason: 'bare specifier matches no workspace package and is not installed' });
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** A config package's entry: its manifest `main`, else a conventional filename. */
|
|
349
|
+
function workspaceEntry(wsDir: string): string | null {
|
|
350
|
+
const manifest = readConfigObject(path.join(wsDir, 'package.json'));
|
|
351
|
+
if (manifest.kind === 'ok' && typeof manifest.value.main === 'string') {
|
|
352
|
+
const viaMain = firstExistingFile(path.join(wsDir, manifest.value.main));
|
|
353
|
+
if (viaMain) return viaMain;
|
|
354
|
+
}
|
|
355
|
+
return firstExistingFile(wsDir);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Follow `extends` / `includes` from one config file and report the whole chain.
|
|
360
|
+
*
|
|
361
|
+
* The returned `hops` always contain at least the starting file, so a caller
|
|
362
|
+
* that finds `digestible` empty can still say WHICH file it read and why nothing
|
|
363
|
+
* came of it. `startPath` is repository-relative.
|
|
364
|
+
*/
|
|
365
|
+
export function resolveConfigChain(repoRoot: string, startPath: string): ChainResolution {
|
|
366
|
+
const workspaces = listWorkspacePackages(repoRoot);
|
|
367
|
+
const hops: ConfigHop[] = [];
|
|
368
|
+
const seen = new Set<string>();
|
|
369
|
+
const queue: ConfigHop[] = [];
|
|
370
|
+
|
|
371
|
+
const startAbs = path.resolve(repoRoot, startPath);
|
|
372
|
+
if (!fs.existsSync(startAbs)) {
|
|
373
|
+
hops.push({ specifier: '', path: startPath, origin: 'unresolved', reason: 'starting config does not exist' });
|
|
374
|
+
} else {
|
|
375
|
+
const { origin, reason } = classify(repoRoot, startAbs);
|
|
376
|
+
queue.push({
|
|
377
|
+
specifier: '',
|
|
378
|
+
path: path.relative(repoRoot, startAbs),
|
|
379
|
+
origin,
|
|
380
|
+
...(reason === undefined ? {} : { reason }),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
while (queue.length > 0) {
|
|
385
|
+
const hop = queue.shift() as ConfigHop;
|
|
386
|
+
if (hops.length >= MAX_HOPS) {
|
|
387
|
+
hops.push({ ...hop, origin: 'unresolved', reason: `chain exceeds ${MAX_HOPS} hops` });
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
const abs = path.resolve(repoRoot, hop.path as string); // non-null: unresolved hops are never queued
|
|
391
|
+
if (seen.has(abs)) {
|
|
392
|
+
hops.push({ ...hop, origin: 'unresolved', reason: 'cycle: this file is already in the chain' });
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
seen.add(abs);
|
|
396
|
+
|
|
397
|
+
const read = readConfigObject(abs);
|
|
398
|
+
if (read.kind !== 'ok') {
|
|
399
|
+
const reason = read.kind === 'absent' ? 'file disappeared between resolution and read' : read.reason;
|
|
400
|
+
hops.push({ ...hop, origin: 'unresolved', reason });
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
hops.push(hop);
|
|
404
|
+
// An external hop's own directives are not followed. Its rules are
|
|
405
|
+
// already excluded from the digest, so walking deeper would only grow
|
|
406
|
+
// the report with paths the project does not own.
|
|
407
|
+
if (hop.origin === 'external') continue;
|
|
408
|
+
for (const specifier of directives(read.value)) {
|
|
409
|
+
const next = resolveSpecifier(repoRoot, path.dirname(abs), specifier, workspaces);
|
|
410
|
+
// A hop the specifier resolver could not place has no path to read,
|
|
411
|
+
// so it is RECORDED and not queued. Queueing it walked into
|
|
412
|
+
// `path.resolve(root, null)` and threw — which turned a partial
|
|
413
|
+
// digest, the whole point of this module, into a crash on exactly
|
|
414
|
+
// the input it exists to handle gracefully.
|
|
415
|
+
if (next.path === null) {
|
|
416
|
+
hops.push(next);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
queue.push(next);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const unresolved = hops.filter((h) => h.origin === 'unresolved');
|
|
424
|
+
return {
|
|
425
|
+
hops,
|
|
426
|
+
complete: unresolved.length === 0,
|
|
427
|
+
digestible: hops.filter((h) => h.origin === 'project' || h.origin === 'workspace-package'),
|
|
428
|
+
externals: hops.filter((h) => h.origin === 'external'),
|
|
429
|
+
unresolved,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export interface NearestConfigResult {
|
|
434
|
+
/** The config that governs `editPath`, repository-relative. `null` = none. */
|
|
435
|
+
governing: string | null;
|
|
436
|
+
/** Every candidate found walking up, nearest first. The precedence order. */
|
|
437
|
+
candidates: string[];
|
|
438
|
+
/** Which rule decided: nearest-wins, root-only, or none-found. */
|
|
439
|
+
basis: 'nearest-wins' | 'root-only' | 'none-found';
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Answer which config governs an edit, given the config filenames to look for.
|
|
444
|
+
*
|
|
445
|
+
* Precedence is **nearest-first**: the file in the edited path's own directory
|
|
446
|
+
* governs, then its parent, up to the repository root. This is not a preference
|
|
447
|
+
* — it is what the tools do. A per-package `tsconfig.json`, `.eslintrc`, `.env`
|
|
448
|
+
* or deployment manifest is the one its own package's build reads, and a root
|
|
449
|
+
* file it does not extend has no effect on it. Reading the root config for an
|
|
450
|
+
* edit inside a package that carries its own is a wrong answer, not a coarse one.
|
|
451
|
+
*
|
|
452
|
+
* `candidates` is the full walk rather than just the winner, because a reader
|
|
453
|
+
* needs to see that a root config was found and outranked before they trust the
|
|
454
|
+
* per-package answer.
|
|
455
|
+
*/
|
|
456
|
+
export function nearestConfig(repoRoot: string, editPath: string, filenames: string[]): NearestConfigResult {
|
|
457
|
+
const candidates: string[] = [];
|
|
458
|
+
const startAbs = path.resolve(repoRoot, editPath);
|
|
459
|
+
let dir = isDir(startAbs) ? startAbs : path.dirname(startAbs);
|
|
460
|
+
const rootAbs = path.resolve(repoRoot);
|
|
461
|
+
|
|
462
|
+
for (;;) {
|
|
463
|
+
for (const name of filenames) {
|
|
464
|
+
const candidate = path.join(dir, name);
|
|
465
|
+
if (fs.existsSync(candidate) && !isDir(candidate)) candidates.push(path.relative(rootAbs, candidate));
|
|
466
|
+
}
|
|
467
|
+
if (dir === rootAbs) break;
|
|
468
|
+
const parent = path.dirname(dir);
|
|
469
|
+
if (parent === dir || !parent.startsWith(rootAbs)) break;
|
|
470
|
+
dir = parent;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (candidates.length === 0) return { governing: null, candidates, basis: 'none-found' };
|
|
474
|
+
const governing = candidates[0] as string;
|
|
475
|
+
const basis = candidates.length === 1 && !governing.includes('/') ? 'root-only' : 'nearest-wins';
|
|
476
|
+
return { governing, candidates, basis };
|
|
477
|
+
}
|