@event4u/agent-config 8.4.0 → 8.5.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 +73 -0
- package/README.md +17 -5
- package/dist/agent-src/README.md +1 -1
- package/dist/agent-src/commands/{analyze-reference-repo.md → analyze/reference-repo.md} +3 -1
- package/dist/agent-src/commands/analyze.md +9 -6
- package/dist/agent-src/commands/{bug-fix.md → bug/fix.md} +3 -1
- package/dist/agent-src/commands/{bug-investigate.md → bug/investigate.md} +4 -2
- package/dist/agent-src/commands/bug.md +59 -0
- package/dist/agent-src/commands/{set-cost-profile.md → cost/profile.md} +9 -6
- package/dist/agent-src/commands/{cost-report.md → cost/report.md} +18 -17
- package/dist/agent-src/commands/cost.md +57 -0
- package/dist/agent-src/commands/evals/{review-changes.json → review.json} +12 -8
- package/dist/agent-src/commands/{quality-fix.md → fix/quality.md} +5 -2
- package/dist/agent-src/commands/fix.md +7 -4
- package/dist/agent-src/commands/optimize/project.md +250 -0
- package/dist/agent-src/commands/{optimize-prompt.md → optimize/prompt.md} +3 -2
- package/dist/agent-src/commands/optimize.md +17 -12
- package/dist/agent-src/commands/{package-reset.md → package/reset.md} +2 -0
- package/dist/agent-src/commands/{package-test.md → package/test.md} +3 -1
- package/dist/agent-src/commands/package.md +56 -0
- package/dist/agent-src/commands/{project-analyze.md → project/analyze.md} +10 -8
- package/dist/agent-src/commands/{project-health.md → project/health.md} +2 -0
- package/dist/agent-src/commands/project.md +60 -0
- package/dist/agent-src/commands/{review-changes.md → review/changes.md} +26 -24
- package/dist/agent-src/commands/{review-routing.md → review/routing.md} +21 -17
- package/dist/agent-src/commands/review.md +61 -0
- package/dist/agent-src/commands/security-audit-config.md +24 -23
- package/dist/agent-src/commands/{sync-agent-settings.md → sync/agent-settings.md} +11 -7
- package/dist/agent-src/commands/{sync-gitignore → sync/gitignore}/fix.md +36 -27
- package/dist/agent-src/commands/{sync-gitignore.md → sync/gitignore.md} +22 -21
- package/dist/agent-src/commands/sync.md +58 -0
- package/dist/agent-src/commands/{e2e-heal.md → tests/e2e-heal.md} +5 -2
- package/dist/agent-src/commands/{e2e-plan.md → tests/e2e-plan.md} +5 -2
- package/dist/agent-src/commands/tests.md +11 -5
- package/dist/agent-src/contexts/augment-infrastructure.md +3 -3
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
- package/dist/agent-src/contexts/skills-and-commands.md +2 -2
- package/dist/agent-src/rules/external-reference-deep-dive.md +1 -1
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
- package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-code-quality/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-security-auditor/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-test-coverage/SKILL.md +1 -1
- package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
- package/dist/agent-src/skills/mobile-e2e-strategy/SKILL.md +5 -5
- package/dist/agent-src/skills/prompt-optimizer/SKILL.md +2 -2
- package/dist/agent-src/skills/quality-tools/SKILL.md +1 -1
- 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/verify-repair-loop/SKILL.md +2 -2
- package/dist/agent-src/templates/agent-settings.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +2 -2
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +1 -1
- package/dist/cli/commands/config.js +44 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/uiServe.js +1 -0
- package/dist/cli/commands/uiServe.js.map +1 -1
- package/dist/cli/help.js +38 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/initRouting.js +16 -1
- package/dist/cli/initRouting.js.map +1 -1
- package/dist/cli/main.js +43 -37
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/registry.js +45 -44
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +419 -210
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +31 -25
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +30 -24
- package/dist/install/install.mjs +6064 -159
- package/dist/install/selectedTools.js +39 -10
- package/dist/install/selectedTools.js.map +1 -1
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/server/app.js +15 -3
- package/dist/server/app.js.map +1 -1
- package/dist/server/routes/ping.js +16 -0
- package/dist/server/routes/ping.js.map +1 -1
- package/dist/server/routes/settings.js +42 -6
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/routes/settingsChanges.js +55 -0
- package/dist/server/routes/settingsChanges.js.map +1 -0
- package/dist/server/routes/userMd.js +7 -2
- package/dist/server/routes/userMd.js.map +1 -1
- package/dist/server/routes/wizard.js +76 -14
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/server/writeRoot.js +17 -0
- package/dist/server/writeRoot.js.map +1 -1
- package/dist/shared/settingsSurface.js +120 -0
- package/dist/shared/settingsSurface.js.map +1 -0
- package/dist/ui/assets/index-BPFMZWUs.css +1 -0
- package/dist/ui/assets/index-BiEZiZ31.js +40 -0
- package/dist/ui/assets/index-BiEZiZ31.js.map +1 -0
- package/dist/ui/index.html +15 -2
- package/docs/CLAIMS.md +20 -15
- package/docs/architecture.md +1 -1
- package/docs/catalog.md +37 -31
- package/docs/command-flows.md +22 -16
- package/docs/contracts/command-clusters.md +39 -9
- package/docs/contracts/file-ownership-matrix.json +21 -0
- package/docs/contracts/frontmatter-contract.md +1 -1
- package/docs/contracts/gui-wizard.md +16 -4
- package/docs/contracts/iron-law-overrides.txt +1 -0
- package/docs/contracts/rule-classification.md +2 -2
- package/docs/contracts/settings-api.md +58 -2
- package/docs/contracts/surface-matrix.md +5 -0
- package/docs/cookbook.md +7 -7
- package/docs/decisions/ADR-114-commit-policy-iron-law-override.md +74 -0
- package/docs/decisions/ADR-115-command-cluster-consolidation-phase-4.md +91 -0
- package/docs/decisions/INDEX.md +2 -0
- package/docs/featured-commands.md +1 -1
- package/docs/featured-skills.md +4 -4
- package/docs/flows.md +2 -2
- package/docs/getting-started-by-role.md +1 -1
- package/docs/getting-started-laravel.md +1 -1
- package/docs/getting-started.md +6 -3
- package/docs/governance-advantage.md +1 -1
- package/docs/guidelines/agent-infra/5w2h-analysis.md +1 -1
- package/docs/guidelines/agent-infra/ios-simulator-guide.md +1 -1
- package/docs/proof.md +11 -2
- package/package.json +6 -1
- package/src/agent-src/README.md +64 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +497 -0
- package/src/agent-src/scripts/scan-seeder-violations.php +145 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +1087 -0
- package/src/agent-src/templates/AGENTS.md +34 -0
- package/src/agent-src/templates/scripts/README.md +195 -0
- package/src/agent-src/templates/scripts/check_memory.ts +662 -0
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +370 -0
- package/src/agent-src/templates/scripts/historical-bug-patterns.example.yml +84 -0
- package/src/agent-src/templates/scripts/implement_ticket/__main__.ts +27 -0
- package/src/agent-src/templates/scripts/memory_hash.ts +355 -0
- package/src/agent-src/templates/scripts/memory_lookup.ts +1089 -0
- package/src/agent-src/templates/scripts/memory_report.ts +868 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +444 -0
- package/src/agent-src/templates/scripts/memory_status.ts +215 -0
- package/src/agent-src/templates/scripts/ownership-map.example.yml +87 -0
- package/src/agent-src/templates/scripts/pr-risk-config.example.yml +76 -0
- package/src/agent-src/templates/scripts/pr_review_routing.ts +544 -0
- 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/telemetry/boundary.ts +164 -0
- package/src/agent-src/templates/scripts/telemetry/engagement.ts +479 -0
- package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +394 -0
- package/src/agent-src/templates/scripts/telemetry/settings.ts +210 -0
- package/src/agent-src/templates/scripts/telemetry_record.ts +276 -0
- package/src/agent-src/templates/scripts/telemetry_report.ts +211 -0
- package/src/agent-src/templates/scripts/telemetry_status.ts +333 -0
- package/src/agent-src/templates/scripts/tier_usage_report.ts +619 -0
- package/src/agent-src/templates/scripts/work_engine/__main__.ts +14 -0
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +1261 -0
- package/src/agent-src/templates/scripts/work_engine/_lib/user_global_paths.ts +329 -0
- package/src/agent-src/templates/scripts/work_engine/cli.ts +206 -0
- package/src/agent-src/templates/scripts/work_engine/cli_args.ts +249 -0
- package/src/agent-src/templates/scripts/work_engine/delivery_state.ts +225 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/analyze.ts +125 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +189 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +94 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/memory.ts +193 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/plan.ts +267 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/refine.ts +518 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/report.ts +379 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +268 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +258 -0
- package/src/agent-src/templates/scripts/work_engine/directives/index.ts +32 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/contract.ts +243 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/index.ts +108 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +259 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/ui.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/_passthrough.ts +40 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +241 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +506 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +325 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/index.ts +102 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +462 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +474 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +352 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.ts +33 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.ts +213 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/index.ts +111 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.ts +126 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/report.ts +112 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/test.ts +164 -0
- package/src/agent-src/templates/scripts/work_engine/dispatcher.ts +515 -0
- package/src/agent-src/templates/scripts/work_engine/emitters.ts +119 -0
- package/src/agent-src/templates/scripts/work_engine/errors.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/hook_bootstrap.ts +104 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.ts +189 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.ts +41 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.ts +89 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.ts +193 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +304 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.ts +110 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.ts +118 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/index.ts +17 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +161 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.ts +45 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/trace.ts +134 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/context.ts +94 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/events.ts +58 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/exceptions.ts +85 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/index.ts +27 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/registry.ts +66 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/runner.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +260 -0
- package/src/agent-src/templates/scripts/work_engine/input_builders.ts +260 -0
- package/src/agent-src/templates/scripts/work_engine/intent/classify.ts +466 -0
- package/src/agent-src/templates/scripts/work_engine/migration/v0_to_v1.ts +531 -0
- package/src/agent-src/templates/scripts/work_engine/orchestration.ts +366 -0
- package/src/agent-src/templates/scripts/work_engine/persona_policy.ts +97 -0
- package/src/agent-src/templates/scripts/work_engine/resolvers/diff.ts +135 -0
- package/src/agent-src/templates/scripts/work_engine/resolvers/file.ts +175 -0
- package/src/agent-src/templates/scripts/work_engine/resolvers/prompt.ts +115 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/confidence.ts +415 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +466 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_trace.ts +298 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +444 -0
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +252 -0
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +745 -0
- package/src/agent-src/templates/scripts/work_engine/state.ts +1151 -0
- package/src/agent-src/templates/scripts/work_engine/state_io.ts +413 -0
- package/src/config/agent-settings.template.yml +1 -1
- package/src/install/atomic.ts +111 -0
- package/src/install/conflict.ts +226 -0
- package/src/install/detect.ts +280 -0
- package/src/install/paths.ts +90 -0
- package/src/install/plan.ts +205 -0
- package/src/install/preflight.ts +210 -0
- package/src/install/selectedTools.ts +80 -0
- package/src/install/toolDetection.ts +120 -0
- package/src/install/txlog.ts +161 -0
- package/src/install/types.ts +175 -0
- package/src/install/wizard-plan.ts +216 -0
- package/src/scripts/_cli/cmd_converge.ts +38 -0
- package/src/scripts/_cli/cmd_doctor.ts +113 -2
- package/src/scripts/_cli/cmd_explain.ts +2 -2
- package/src/scripts/_cli/cmd_export.ts +3 -3
- package/src/scripts/_cli/cmd_fleet.ts +13 -1
- package/src/scripts/_cli/cmd_migrate.ts +3 -3
- package/src/scripts/_cli/cmd_prune.ts +2 -2
- package/src/scripts/_cli/cmd_refresh.ts +4 -4
- package/src/scripts/_cli/cmd_settings_check.ts +2 -2
- package/src/scripts/_cli/cmd_settings_migrate.ts +2 -2
- package/src/scripts/_cli/cmd_sync.ts +2 -2
- package/src/scripts/_cli/cmd_uninstall.ts +2 -2
- package/src/scripts/_cli/cmd_update.ts +8 -8
- package/src/scripts/_cli/cmd_upgrade.ts +4 -3
- package/src/scripts/_cli/cmd_validate.ts +3 -3
- package/src/scripts/_cli/cmd_versions.ts +2 -2
- package/src/scripts/_cli/explain_last/assumptions.ts +2 -2
- package/src/scripts/_cli/explain_last/council.ts +2 -2
- package/src/scripts/_cli/explain_last/halt.ts +2 -2
- package/src/scripts/_cli/explain_last/index.ts +2 -2
- package/src/scripts/_cli/explain_last/inputs.ts +4 -4
- package/src/scripts/_cli/explain_last/memory.ts +2 -2
- package/src/scripts/_cli/explain_last/provider.ts +2 -2
- package/src/scripts/_cli/explain_last/render.ts +2 -2
- package/src/scripts/_cli/explain_last/route.ts +2 -2
- package/src/scripts/_cli/explain_last/scrubber.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/assumptions.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/council.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/halt.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/header.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/index.ts +1 -1
- package/src/scripts/_cli/explain_last/sections/inputs.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/memory.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/pack.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/provider.ts +2 -2
- package/src/scripts/_cli/explain_last/sections/route.ts +2 -2
- package/src/scripts/_cli/explain_last/state_loader.ts +2 -2
- package/src/scripts/_dispatch.bash +20 -1
- package/src/scripts/_lib/agent_settings.ts +1 -1
- package/src/scripts/_lib/agent_src.ts +7 -7
- package/src/scripts/_lib/agents_overlay.ts +1 -1
- package/src/scripts/_lib/bench_ab_cache.ts +1 -1
- package/src/scripts/_lib/bench_ab_scoring.ts +1 -1
- package/src/scripts/_lib/bench_ab_scoring_v2.ts +3 -3
- package/src/scripts/_lib/bench_cost.ts +1 -1
- package/src/scripts/_lib/bench_quality.ts +3 -3
- package/src/scripts/_lib/bench_report.ts +4 -4
- package/src/scripts/_lib/bench_telegraph.ts +1 -1
- package/src/scripts/_lib/bench_telegraph_report.ts +4 -4
- package/src/scripts/_lib/changelog_eras.ts +1 -1
- package/src/scripts/_lib/claude_desktop_bundler.ts +1 -1
- package/src/scripts/_lib/cli_wrapper.ts +1 -1
- package/src/scripts/_lib/fs_atomic.ts +1 -1
- package/src/scripts/_lib/global_deploy_inventory.ts +1 -1
- package/src/scripts/_lib/install_layout.ts +1 -1
- package/src/scripts/_lib/install_regenerator.ts +1 -1
- package/src/scripts/_lib/installed_lock.ts +1 -1
- package/src/scripts/_lib/installed_tools.ts +1 -1
- package/src/scripts/_lib/json_pointers.ts +1 -1
- package/src/scripts/_lib/knowledge_global.ts +1 -1
- package/src/scripts/_lib/knowledge_global_promote.ts +2 -2
- package/src/scripts/_lib/knowledge_global_redaction.ts +2 -2
- package/src/scripts/_lib/link_crypto.ts +4 -4
- package/src/scripts/_lib/linked_projects.ts +4 -4
- package/src/scripts/_lib/model_tier.ts +1 -1
- package/src/scripts/_lib/module_detection.ts +2 -2
- package/src/scripts/_lib/pin_resolver.ts +1 -1
- package/src/scripts/_lib/script_output.ts +1 -1
- package/src/scripts/_lib/security_lint.ts +1 -1
- package/src/scripts/_lib/surface_tiers.ts +1 -1
- package/src/scripts/_lib/text_similarity.ts +1 -1
- package/src/scripts/_lib/update_check.ts +2 -2
- package/src/scripts/_lib/user_global_paths.ts +1 -1
- package/src/scripts/_lib/value_ladder.ts +1 -1
- package/src/scripts/_lib/value_report.ts +1 -1
- package/src/scripts/_lib/zip_min.ts +2 -2
- package/src/scripts/adoption_report.ts +3 -3
- package/src/scripts/adoption_snapshot.ts +3 -3
- package/src/scripts/adoption_status.ts +2 -2
- package/src/scripts/adr/regenerate_index.ts +3 -3
- package/src/scripts/ai_council/_default_prices.ts +2 -3
- package/src/scripts/ai_council/advisors.ts +1 -1
- package/src/scripts/ai_council/airgap.ts +1 -1
- package/src/scripts/ai_council/budget_guard.ts +1 -1
- package/src/scripts/ai_council/bundler.ts +1 -1
- package/src/scripts/ai_council/cli_hints.ts +1 -1
- package/src/scripts/ai_council/clients.ts +5 -5
- package/src/scripts/ai_council/compile_corpus.ts +1 -1
- package/src/scripts/ai_council/confidence_gate.ts +1 -1
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/consensus.ts +1 -1
- package/src/scripts/ai_council/events_log.ts +1 -1
- package/src/scripts/ai_council/learn_low_impact_preview.ts +1 -1
- package/src/scripts/ai_council/low_impact_corpus.ts +1 -1
- package/src/scripts/ai_council/low_impact_intake.ts +1 -1
- package/src/scripts/ai_council/modes.ts +1 -1
- package/src/scripts/ai_council/orchestrator.ts +3 -3
- package/src/scripts/ai_council/pricing.ts +2 -2
- package/src/scripts/ai_council/probation_gate.ts +2 -2
- package/src/scripts/ai_council/project_context.ts +1 -1
- package/src/scripts/ai_council/prompts.ts +1 -1
- package/src/scripts/ai_council/redact_low_impact_entry.ts +2 -2
- package/src/scripts/ai_council/session.ts +1 -1
- package/src/scripts/ai_council/shadow_dispatch.ts +1 -1
- package/src/scripts/ai_council/solo_dispatch.ts +1 -1
- package/src/scripts/analysis_freshness.ts +2 -2
- package/src/scripts/annotate_discovery.ts +2 -2
- package/src/scripts/apply_modules_config.ts +2 -2
- package/src/scripts/audit_adr_coverage.ts +3 -3
- package/src/scripts/audit_auto_rules.ts +2 -2
- package/src/scripts/audit_cloud_compatibility.ts +3 -3
- package/src/scripts/audit_command_surface.ts +2 -2
- package/src/scripts/audit_initial_context.ts +7 -6
- package/src/scripts/audit_likelihood.ts +5 -5
- package/src/scripts/audit_mcp_tools.ts +3 -3
- package/src/scripts/audit_overlap.ts +2 -2
- package/src/scripts/audit_skill_descriptions.ts +2 -2
- package/src/scripts/audit_skill_overlap.ts +5 -5
- package/src/scripts/audit_user_type_axis.ts +4 -4
- package/src/scripts/backfill_model_tier.ts +1 -1
- package/src/scripts/bench_ab_cache_dispatch.ts +2 -2
- package/src/scripts/bench_ab_clone.ts +2 -2
- package/src/scripts/bench_ab_diff.ts +3 -3
- package/src/scripts/bench_ab_integrity.ts +2 -2
- package/src/scripts/bench_ab_run.ts +4 -4
- package/src/scripts/bench_ab_task_runner.ts +1 -1
- package/src/scripts/bench_ab_tracka_run.ts +2 -2
- package/src/scripts/bench_ab_v2_run.ts +1 -1
- package/src/scripts/bench_ab_v2_stats.ts +2 -2
- package/src/scripts/bench_baseline_ready.ts +1 -1
- package/src/scripts/bench_condense_memory.ts +4 -4
- package/src/scripts/bench_drift_check.ts +3 -3
- package/src/scripts/bench_per_tool.ts +1 -1
- package/src/scripts/bench_rtk_savings.ts +4 -4
- package/src/scripts/bench_run.ts +4 -4
- package/src/scripts/bench_runner.ts +1 -1
- package/src/scripts/build_cloud_bundle.ts +3 -3
- package/src/scripts/build_discovery_manifest.ts +13 -15
- package/src/scripts/build_linear_digest.ts +2 -2
- package/src/scripts/build_mcp_registry_manifest.ts +3 -3
- package/src/scripts/build_proof.ts +6 -0
- package/src/scripts/build_rule_trigger_matrix.ts +2 -2
- package/src/scripts/capture_showcase_session.ts +3 -3
- package/src/scripts/chat_history.ts +1 -1
- package/src/scripts/check_always_budget.ts +1 -1
- package/src/scripts/check_artefact_checksums.ts +4 -4
- package/src/scripts/check_artefact_count_messaging.ts +197 -0
- package/src/scripts/check_augment_description_cap.ts +3 -3
- package/src/scripts/check_augmentignore.ts +1 -1
- package/src/scripts/check_beta_review_markers.ts +3 -3
- package/src/scripts/check_bite_sized_granularity.ts +1 -1
- package/src/scripts/check_cluster_patterns.ts +47 -3
- package/src/scripts/check_command_count_messaging.ts +2 -2
- package/src/scripts/check_condensation.ts +2 -2
- package/src/scripts/check_condensed_paths.ts +6 -6
- package/src/scripts/check_context_paths.ts +1 -1
- package/src/scripts/check_council_config_location.ts +3 -3
- package/src/scripts/check_council_layout.ts +2 -2
- package/src/scripts/check_council_references.ts +2 -2
- package/src/scripts/check_discovery_determinism.ts +3 -3
- package/src/scripts/check_gate_paths.ts +4 -4
- package/src/scripts/check_iron_law_prominence.ts +2 -2
- package/src/scripts/check_kernel_rule_bundle.ts +3 -3
- package/src/scripts/check_knowledge_cards.ts +4 -4
- package/src/scripts/check_knowledge_pages.ts +1 -1
- package/src/scripts/check_md_language.ts +3 -3
- package/src/scripts/check_memory.ts +3 -3
- package/src/scripts/check_memory_proposal.ts +2 -2
- package/src/scripts/check_module_management_neutral.ts +1 -1
- package/src/scripts/check_no_conflict_markers.ts +1 -1
- package/src/scripts/check_no_external_sources.ts +1 -1
- package/src/scripts/check_no_local_settings_committed.ts +2 -2
- package/src/scripts/check_no_new_legacy_path.ts +3 -3
- package/src/scripts/check_no_roadmap_refs.ts +3 -3
- package/src/scripts/check_one_off_location.ts +3 -3
- package/src/scripts/check_overlay_cascade_subdirs.ts +3 -3
- package/src/scripts/check_portability.ts +3 -3
- package/src/scripts/check_proposal.ts +0 -0
- package/src/scripts/check_public_catalog_links.ts +1 -1
- package/src/scripts/check_public_links.ts +2 -2
- package/src/scripts/check_references.ts +3 -3
- package/src/scripts/check_release_includes_discovery.ts +2 -2
- package/src/scripts/check_release_pr_shape.ts +2 -2
- package/src/scripts/check_release_published.ts +1 -1
- package/src/scripts/check_release_trunk_sync.ts +3 -3
- package/src/scripts/check_reply_consistency.ts +1 -1
- package/src/scripts/check_roadmap_trackable.ts +2 -2
- package/src/scripts/check_role_doc_links.ts +2 -2
- package/src/scripts/check_safety_floor_untouched.ts +3 -3
- package/src/scripts/check_skill_requires.ts +2 -2
- package/src/scripts/check_structural_breaking.ts +2 -2
- package/src/scripts/check_surface_tiers.ts +2 -2
- package/src/scripts/check_template_pin_drift.ts +1 -1
- package/src/scripts/check_test_coverage_diff.ts +2 -2
- package/src/scripts/check_token_optimizer_freshness.ts +3 -3
- package/src/scripts/check_trigger_evals.ts +2 -2
- package/src/scripts/check_update_banner.ts +1 -1
- package/src/scripts/ci_status.ts +0 -0
- package/src/scripts/ci_summary.ts +3 -3
- package/src/scripts/ci_time_ratio.ts +1 -1
- package/src/scripts/command_suggester/cooldown.ts +1 -1
- package/src/scripts/command_suggester/index.ts +1 -1
- package/src/scripts/command_suggester/loader.ts +1 -1
- package/src/scripts/command_suggester/match.ts +1 -1
- package/src/scripts/command_suggester/rank.ts +1 -1
- package/src/scripts/command_suggester/render.ts +1 -1
- package/src/scripts/command_suggester/sanitize.ts +1 -1
- package/src/scripts/command_suggester/settings.ts +1 -1
- package/src/scripts/command_suggester/types.ts +0 -0
- package/src/scripts/compile_router.ts +4 -4
- package/src/scripts/condense.ts +3 -3
- package/src/scripts/condense_memory.ts +1 -1
- package/src/scripts/config/index.ts +1 -1
- package/src/scripts/config/packs.ts +1 -1
- package/src/scripts/config/presets.ts +1 -1
- package/src/scripts/config/profile_explain.ts +1 -1
- package/src/scripts/config/profiles.ts +1 -1
- package/src/scripts/config/session_profiles.ts +1 -1
- package/src/scripts/context_hygiene_hook.ts +2 -2
- package/src/scripts/cost_by_conversation.ts +1 -1
- package/src/scripts/cost_summary.ts +2 -2
- package/src/scripts/council_cli.ts +1 -1
- package/src/scripts/council_prune.ts +1 -1
- package/src/scripts/cross_repo_retrieve.ts +2 -2
- package/src/scripts/discovery_stats.ts +3 -3
- package/src/scripts/evidence_report.ts +4 -4
- package/src/scripts/extract_audit_patterns.ts +2 -2
- package/src/scripts/first_run_gate_hook.ts +1 -1
- package/src/scripts/gen_discovery_baseline.ts +2 -2
- package/src/scripts/generate_capabilities_index.ts +2 -2
- package/src/scripts/generate_capability_matrix.ts +2 -2
- package/src/scripts/generate_catalog.ts +2 -2
- package/src/scripts/generate_command_flows.ts +2 -2
- package/src/scripts/generate_cookbook.ts +1 -1
- package/src/scripts/generate_index.ts +3 -3
- package/src/scripts/generate_ownership_matrix.ts +2 -2
- package/src/scripts/generate_pack_manifests.ts +2 -2
- package/src/scripts/generate_role_experiences_catalog.ts +3 -3
- package/src/scripts/hooks/block_no_verify.ts +2 -2
- package/src/scripts/hooks/dispatch_hook.ts +2 -2
- package/src/scripts/hooks/dispatch_issues.ts +1 -1
- package/src/scripts/hooks/envelope.ts +1 -1
- package/src/scripts/hooks/replay_hook.ts +1 -1
- package/src/scripts/hooks/state_io.ts +1 -1
- package/src/scripts/hooks_doctor.ts +1 -1
- package/src/scripts/hooks_status.ts +1 -1
- package/src/scripts/injection_scan_hook.ts +1 -1
- package/src/scripts/install.ts +145 -3
- package/src/scripts/inventory_abstraction_budget.ts +5 -5
- package/src/scripts/inventory_frontmatter.ts +1 -1
- package/src/scripts/inventory_meta_layers.ts +1 -1
- package/src/scripts/iron_law_sha.ts +1 -1
- package/src/scripts/knowledge_global_cli.ts +3 -3
- package/src/scripts/linked_projects_list.ts +1 -1
- package/src/scripts/lint_agent_security.ts +4 -4
- package/src/scripts/lint_agent_skill_names.ts +1 -1
- package/src/scripts/lint_agents_layout.ts +2 -2
- package/src/scripts/lint_agents_md.ts +3 -3
- package/src/scripts/lint_archived_skills.ts +2 -2
- package/src/scripts/lint_artefact_frontmatter.ts +2 -2
- package/src/scripts/lint_bench_ab.ts +2 -2
- package/src/scripts/lint_bench_corpus.ts +1 -1
- package/src/scripts/lint_command_flow_coverage.ts +1 -1
- package/src/scripts/lint_command_routing.ts +2 -2
- package/src/scripts/lint_command_tiers.ts +1 -1
- package/src/scripts/lint_command_verbs.ts +4 -4
- package/src/scripts/lint_commit_subjects.ts +2 -2
- package/src/scripts/lint_context_spine_usage.ts +3 -3
- package/src/scripts/lint_discovery_manifest.ts +4 -4
- package/src/scripts/lint_discovery_vocabulary.ts +2 -2
- package/src/scripts/lint_empty_roadmaps.ts +3 -3
- package/src/scripts/lint_eval_freshness.ts +2 -2
- package/src/scripts/lint_examples.ts +2 -2
- package/src/scripts/lint_explain_trace.ts +2 -2
- package/src/scripts/lint_featured_skills.ts +0 -0
- package/src/scripts/lint_flows.ts +5 -5
- package/src/scripts/lint_framework_leakage.ts +1 -1
- package/src/scripts/lint_framework_leakage_allowlist.json +10 -2
- package/src/scripts/lint_frontmatter_boilerplate.ts +2 -2
- package/src/scripts/lint_ghostwriter_source.ts +3 -3
- package/src/scripts/lint_global_paths.ts +1 -1
- package/src/scripts/lint_handoffs.ts +1 -1
- package/src/scripts/lint_hidden_unicode.ts +1 -1
- package/src/scripts/lint_hook_concern_budget.ts +2 -2
- package/src/scripts/lint_hook_manifest.ts +2 -2
- package/src/scripts/lint_instruction_smuggling.ts +1 -1
- package/src/scripts/lint_load_context.ts +2 -2
- package/src/scripts/lint_marketplace.ts +1 -1
- package/src/scripts/lint_marketplace_install_completeness.ts +2 -2
- package/src/scripts/lint_mcp_config_security.ts +1 -1
- package/src/scripts/lint_mcp_registry_manifest.ts +1 -1
- package/src/scripts/lint_media_policy_linkage.ts +3 -3
- package/src/scripts/lint_missions.ts +3 -3
- package/src/scripts/lint_model_tier_coverage.ts +3 -3
- package/src/scripts/lint_namespace.ts +2 -2
- package/src/scripts/lint_namespace_collisions.ts +2 -2
- package/src/scripts/lint_new_skill_gate.ts +3 -3
- package/src/scripts/lint_no_new_atomic_commands.ts +9 -6
- package/src/scripts/lint_no_python_twin_rationale.ts +102 -0
- package/src/scripts/lint_one_off_age.ts +2 -2
- package/src/scripts/lint_orchestration_dsl.ts +3 -3
- package/src/scripts/lint_orchestrator_auto_detect.ts +1 -1
- package/src/scripts/lint_pack_boundaries.ts +2 -2
- package/src/scripts/lint_pack_dependencies.ts +2 -2
- package/src/scripts/lint_pack_first_win.ts +2 -2
- package/src/scripts/lint_persona_governance.ts +3 -3
- package/src/scripts/lint_positioning.ts +1 -1
- package/src/scripts/lint_profile_overlay_set_only.ts +2 -2
- package/src/scripts/lint_readme_jargon.ts +2 -2
- package/src/scripts/lint_readme_size.ts +2 -2
- package/src/scripts/lint_regression.ts +3 -3
- package/src/scripts/lint_roadmap_ci_steps.ts +3 -3
- package/src/scripts/lint_roadmap_complexity.ts +1 -1
- package/src/scripts/lint_roadmap_later_disposition.ts +2 -2
- package/src/scripts/lint_role_experiences.ts +2 -2
- package/src/scripts/lint_rule_interactions.ts +1 -1
- package/src/scripts/lint_rule_tiers.ts +1 -1
- package/src/scripts/lint_showcase_sessions.ts +2 -2
- package/src/scripts/lint_skill_frontmatter_safety.ts +1 -1
- package/src/scripts/lint_skill_originality.ts +1 -1
- package/src/scripts/lint_skill_tools.ts +3 -3
- package/src/scripts/lint_ticket_buildable.ts +2 -2
- package/src/scripts/lint_topics_yaml.ts +3 -3
- package/src/scripts/lint_trust_coherence.ts +3 -3
- package/src/scripts/lint_value_dashboard.ts +3 -3
- package/src/scripts/lint_workflow_security.ts +3 -3
- package/src/scripts/lint_workspace_boundary.ts +2 -2
- package/src/scripts/mcp_parity_smoke.ts +1 -1
- package/src/scripts/mcp_render.ts +1 -1
- package/src/scripts/mcp_server/catalog.ts +1 -1
- package/src/scripts/mcp_server/index.ts +1 -1
- package/src/scripts/mcp_server/metadata.ts +1 -1
- package/src/scripts/mcp_server/prompts.ts +1 -1
- package/src/scripts/mcp_server/resources.ts +1 -1
- package/src/scripts/mcp_server/server.ts +1 -1
- package/src/scripts/mcp_server/telemetry.ts +1 -1
- package/src/scripts/mcp_server/tools.ts +1 -1
- package/src/scripts/mcp_telemetry_health.ts +1 -1
- package/src/scripts/mcp_telemetry_query.ts +3 -3
- package/src/scripts/mcp_telemetry_store.ts +3 -3
- package/src/scripts/measure_augment_budget.ts +2 -2
- package/src/scripts/measure_density.ts +2 -2
- package/src/scripts/measure_frugality_savings.ts +3 -3
- package/src/scripts/measure_markitdown_lift.ts +1 -1
- package/src/scripts/measure_patterns.ts +1 -1
- package/src/scripts/measure_projection_bytes.ts +1 -1
- package/src/scripts/measure_rule_budget.ts +1 -1
- package/src/scripts/measure_skill_reduction.ts +1 -1
- package/src/scripts/memory_hash.ts +1 -1
- package/src/scripts/memory_lookup.ts +6 -6
- package/src/scripts/memory_report.ts +1 -1
- package/src/scripts/memory_signal.ts +1 -1
- package/src/scripts/memory_status.ts +2 -2
- package/src/scripts/migrate_command_suggestions.ts +1 -1
- package/src/scripts/migrate_frontmatter_defaults.ts +1 -1
- package/src/scripts/mine_session.ts +3 -3
- package/src/scripts/minimal_safe_diff_hook.ts +2 -2
- package/src/scripts/move_artefact.ts +3 -3
- package/src/scripts/new_skill.ts +3 -3
- package/src/scripts/onboarding_gate_hook.ts +2 -2
- package/src/scripts/pack_mcp_content.ts +1 -1
- package/src/scripts/parity/replay.ts +3 -2
- package/src/scripts/pattern_share.ts +2 -2
- package/src/scripts/plan_physical_move.ts +3 -3
- package/src/scripts/prediction-pool/poisson_sim.ts +2 -2
- package/src/scripts/prediction-pool/pool_winsim.ts +2 -2
- package/src/scripts/prediction-pool/score_ev.ts +2 -2
- package/src/scripts/prepack-check.mjs +108 -5
- package/src/scripts/print_required_checks.ts +2 -2
- package/src/scripts/probe_projection_fidelity.ts +2 -2
- package/src/scripts/probe_skill_registration.ts +2 -2
- package/src/scripts/profile_staleness_hook.ts +2 -2
- package/src/scripts/profile_use.ts +2 -2
- package/src/scripts/project_thin_rules.ts +3 -3
- package/src/scripts/propose_modules_config.ts +2 -2
- package/src/scripts/prototype_lint_contradictions.ts +2 -2
- package/src/scripts/prove_pack_extractable.ts +1 -1
- package/src/scripts/readme_linter.ts +4 -4
- package/src/scripts/redact_hook_capture.ts +2 -2
- package/src/scripts/refine_ticket_detect.ts +1 -1
- package/src/scripts/release.ts +30 -19
- package/src/scripts/render_benchmark_md.ts +2 -2
- package/src/scripts/render_value_md.ts +2 -2
- package/src/scripts/roadmap_progress_hook.ts +1 -1
- package/src/scripts/router_telemetry.ts +1 -1
- package/src/scripts/run_skill_evals.ts +2 -2
- package/src/scripts/runtime_dispatcher.ts +1 -1
- package/src/scripts/runtime_handler.ts +1 -1
- package/src/scripts/runtime_registry.ts +3 -3
- package/src/scripts/score_skill_selection.ts +1 -1
- package/src/scripts/security_audit_config.ts +2 -2
- package/src/scripts/skill_collision_clusters.ts +1 -1
- package/src/scripts/skill_discovery.ts +1 -1
- package/src/scripts/skill_linter.ts +8 -7
- package/src/scripts/skill_overlap.ts +2 -2
- package/src/scripts/skill_preview.ts +1 -1
- package/src/scripts/skill_tools/audit_persona_coverage.ts +3 -3
- package/src/scripts/skill_tools/audit_user_type_coverage.ts +3 -3
- package/src/scripts/skill_tools/index.ts +1 -1
- package/src/scripts/skill_tools/run_block_d_eval.ts +3 -3
- package/src/scripts/skill_tools/score_skill_relevance.ts +3 -3
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +3 -3
- package/src/scripts/skill_trigger_eval.ts +2 -2
- package/src/scripts/skill_usage_collect.ts +2 -2
- package/src/scripts/skill_usage_report.ts +2 -2
- package/src/scripts/smoke_path_resolution.ts +2 -2
- package/src/scripts/smoke_quickstart.ts +4 -4
- package/src/scripts/snapshot_agent_outputs.ts +2 -2
- package/src/scripts/spotcheck_thin_root.ts +2 -2
- package/src/scripts/surface-tiers.yml +1 -0
- package/src/scripts/sync_agent_settings.ts +2 -2
- package/src/scripts/sync_github_metadata.ts +4 -4
- package/src/scripts/sync_gitignore.ts +3 -3
- package/src/scripts/sync_yaml_rt.ts +2 -2
- package/src/scripts/telegraph_stats.ts +1 -1
- package/src/scripts/tool_registry.ts +2 -2
- package/src/scripts/tools/adapter_errors.ts +1 -1
- package/src/scripts/tools/base_adapter.ts +1 -1
- package/src/scripts/tools/github_adapter.ts +1 -1
- package/src/scripts/tools/jira_adapter.ts +1 -1
- package/src/scripts/trigger_coverage.ts +2 -2
- package/src/scripts/update_counts.ts +68 -6
- package/src/scripts/update_prices.ts +3 -3
- package/src/scripts/validate_agent_settings.ts +3 -3
- package/src/scripts/validate_decision_engine.ts +2 -2
- package/src/scripts/validate_discovery_manifest.ts +3 -3
- package/src/scripts/validate_frontmatter.ts +5 -5
- package/src/scripts/validate_pack_yaml.ts +0 -0
- package/src/scripts/validate_safe_paths.ts +2 -2
- package/src/scripts/validate_telegraph_carveouts.ts +3 -3
- package/src/scripts/verify_before_complete_hook.ts +2 -2
- package/src/scripts/verify_physical_move.ts +2 -2
- package/src/scripts/wrapper_freshness_hook.ts +3 -3
- package/src/server/schemas/settings.ts +426 -0
- package/src/shared/settingsSurface.ts +184 -0
- package/src/shared/userMd/formAdapter.ts +86 -0
- package/src/shared/userMd/schema.ts +59 -0
- package/src/shared/userMd/utils.ts +91 -0
- package/dist/agent-src/commands/optimize-project.md +0 -243
- package/dist/ui/assets/index-BbWWuFrF.css +0 -1
- package/dist/ui/assets/index-UjcTG_9O.js +0 -40
- package/dist/ui/assets/index-UjcTG_9O.js.map +0 -1
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toolchain resolution — pick the right test/quality runner per stack.
|
|
3
|
+
*
|
|
4
|
+
* TypeScript twin of `work_engine/stack/runner.py` (ADR-200 py2ts). Leaf
|
|
5
|
+
* module — stdlib only, NO intra-`work_engine` imports — so the public API
|
|
6
|
+
* names stay snake_case to mirror the Python module 1:1 (per ADR-200: Python
|
|
7
|
+
* style is part of the contract).
|
|
8
|
+
*
|
|
9
|
+
* Sibling of {@link "./detect"} (which labels the *frontend* stack). This
|
|
10
|
+
* module answers a different question: *given a project root, which test
|
|
11
|
+
* runner and quality tools does this stack actually use, and what is the
|
|
12
|
+
* exact command to invoke them?* It is the engine behind 6.1.0 Step 6 — the
|
|
13
|
+
* toolchain resolver that lets one set of commands (`/tests execute`,
|
|
14
|
+
* `/tests create`, `/fix quality`, `/review changes`, `/work`) adapt to
|
|
15
|
+
* phpunit / pest / vitest / jest / playwright / pytest / go / cargo instead
|
|
16
|
+
* of exploding into per-stack command variants.
|
|
17
|
+
*
|
|
18
|
+
* Detection is filesystem-cheap and **never crashes**: a malformed manifest,
|
|
19
|
+
* a missing file, or an unknown stack degrades to a LOW-confidence empty
|
|
20
|
+
* result rather than raising — a wrong toolchain label is recoverable (the
|
|
21
|
+
* agent can ask), a crash mid-run is not. This mirrors the recoverable-error
|
|
22
|
+
* contract in {@link "./detect"}.
|
|
23
|
+
*
|
|
24
|
+
* Three opt-in flags shape the *selected* command set (the monorepo guard):
|
|
25
|
+
*
|
|
26
|
+
* - `include_e2e` — by default e2e suites (playwright / cypress) are
|
|
27
|
+
* excluded; fast unit tests run first. Pass to add them.
|
|
28
|
+
* - `include_slow` — by default a script tagged `test:slow` /
|
|
29
|
+
* `test:integration` is excluded. Pass to add it.
|
|
30
|
+
* - `php_only` — keep only the PHP ecosystem (the `--php` narrowing the
|
|
31
|
+
* roadmap calls for; "only genuine PHP-space commands stay PHP-locked").
|
|
32
|
+
*
|
|
33
|
+
* The full per-stack inventory is always returned (`runners`); the
|
|
34
|
+
* `selected` tuple is what a command should actually run after applying
|
|
35
|
+
* the flags + the fast-by-default monorepo guard.
|
|
36
|
+
*/
|
|
37
|
+
import * as fs from 'node:fs';
|
|
38
|
+
import * as path from 'node:path';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Every test-runner label the resolver can emit.
|
|
42
|
+
*
|
|
43
|
+
* Single source of truth so the state schema, fixtures, and tests validate
|
|
44
|
+
* against one set without re-deriving it. Mirrors Python's `frozenset`.
|
|
45
|
+
*/
|
|
46
|
+
export const KNOWN_RUNNERS: ReadonlySet<string> = new Set([
|
|
47
|
+
'pest',
|
|
48
|
+
'phpunit',
|
|
49
|
+
'vitest',
|
|
50
|
+
'jest',
|
|
51
|
+
'playwright',
|
|
52
|
+
'cypress',
|
|
53
|
+
'pytest',
|
|
54
|
+
'go-test',
|
|
55
|
+
'cargo-test',
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
// Speed buckets. `fast` runs by default; `slow` needs `include_slow`;
|
|
59
|
+
// `e2e` needs `include_e2e`. The monorepo guard reads this.
|
|
60
|
+
export const SPEED_FAST = 'fast';
|
|
61
|
+
export const SPEED_SLOW = 'slow';
|
|
62
|
+
export const SPEED_E2E = 'e2e';
|
|
63
|
+
|
|
64
|
+
// Confidence tiers — declarative, mirrors the non-interactive-contract
|
|
65
|
+
// tiers (HIGH = deterministic dependency/marker; MEDIUM = heuristic;
|
|
66
|
+
// LOW = nothing matched).
|
|
67
|
+
export const HIGH = 'HIGH';
|
|
68
|
+
export const MEDIUM = 'MEDIUM';
|
|
69
|
+
export const LOW = 'LOW';
|
|
70
|
+
|
|
71
|
+
const _MANIFESTS = [
|
|
72
|
+
'composer.json',
|
|
73
|
+
'package.json',
|
|
74
|
+
'pyproject.toml',
|
|
75
|
+
'go.mod',
|
|
76
|
+
'Cargo.toml',
|
|
77
|
+
'Makefile',
|
|
78
|
+
'Taskfile.yml',
|
|
79
|
+
'Taskfile.yaml',
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
/** A heterogeneous JSON object, mirroring a Python `dict[str, object]`. */
|
|
83
|
+
type Manifest = { [key: string]: unknown };
|
|
84
|
+
|
|
85
|
+
/** Role → wrapper-command map, mirroring Python's `dict[str, str]`. */
|
|
86
|
+
type Wrappers = { [role: string]: string };
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* One detected test runner for one ecosystem.
|
|
90
|
+
*
|
|
91
|
+
* `command` is the exact invocation to run the suite (a task-runner
|
|
92
|
+
* wrapper like `make test` when one exists, otherwise the direct tool).
|
|
93
|
+
* `speed` is one of {@link SPEED_FAST} / {@link SPEED_SLOW} /
|
|
94
|
+
* {@link SPEED_E2E}; the monorepo guard filters on it. `basis` names the
|
|
95
|
+
* concrete signal that matched (dependency, binary, marker file) so the
|
|
96
|
+
* routing decision is auditable, exactly like the non-interactive-contract's
|
|
97
|
+
* `basis` column.
|
|
98
|
+
*
|
|
99
|
+
* Mirrors the Python `@dataclass(frozen=True)` with positional construction
|
|
100
|
+
* and the documented field defaults.
|
|
101
|
+
*/
|
|
102
|
+
export class RunnerResult {
|
|
103
|
+
readonly ecosystem: string;
|
|
104
|
+
readonly runner: string;
|
|
105
|
+
readonly command: string;
|
|
106
|
+
readonly speed: string;
|
|
107
|
+
readonly confidence: string;
|
|
108
|
+
readonly basis: string;
|
|
109
|
+
|
|
110
|
+
constructor(
|
|
111
|
+
ecosystem: string,
|
|
112
|
+
runner: string,
|
|
113
|
+
command: string,
|
|
114
|
+
speed: string = SPEED_FAST,
|
|
115
|
+
confidence: string = HIGH,
|
|
116
|
+
basis = '',
|
|
117
|
+
) {
|
|
118
|
+
this.ecosystem = ecosystem;
|
|
119
|
+
this.runner = runner;
|
|
120
|
+
this.command = command;
|
|
121
|
+
this.speed = speed;
|
|
122
|
+
this.confidence = confidence;
|
|
123
|
+
this.basis = basis;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Outcome of one toolchain-resolution pass over a project root.
|
|
129
|
+
*
|
|
130
|
+
* `runners` is the full inventory (every ecosystem detected, every speed
|
|
131
|
+
* bucket). `selected` is what a command should actually run after the flags
|
|
132
|
+
* + fast-by-default guard. `quality` is the ordered list of quality/lint
|
|
133
|
+
* commands per detected ecosystem. `confidence` is the overall tier (HIGH
|
|
134
|
+
* when ≥1 runner matched deterministically and no cross-ecosystem conflict;
|
|
135
|
+
* LOW when nothing matched). `mtime` is the latest manifest mtime, used for
|
|
136
|
+
* cache invalidation just like {@link "./detect".StackResult}.
|
|
137
|
+
*/
|
|
138
|
+
export class ToolchainResult {
|
|
139
|
+
readonly ecosystems: readonly string[];
|
|
140
|
+
readonly runners: readonly RunnerResult[];
|
|
141
|
+
readonly selected: readonly RunnerResult[];
|
|
142
|
+
readonly quality: readonly string[];
|
|
143
|
+
readonly confidence: string;
|
|
144
|
+
readonly mtime: number;
|
|
145
|
+
|
|
146
|
+
constructor(args: {
|
|
147
|
+
ecosystems: readonly string[];
|
|
148
|
+
runners: readonly RunnerResult[];
|
|
149
|
+
selected: readonly RunnerResult[];
|
|
150
|
+
quality: readonly string[];
|
|
151
|
+
confidence: string;
|
|
152
|
+
mtime: number;
|
|
153
|
+
}) {
|
|
154
|
+
this.ecosystems = args.ecosystems;
|
|
155
|
+
this.runners = args.runners;
|
|
156
|
+
this.selected = args.selected;
|
|
157
|
+
this.quality = args.quality;
|
|
158
|
+
this.confidence = args.confidence;
|
|
159
|
+
this.mtime = args.mtime;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Serialise to the auto-generated project-config shape.
|
|
164
|
+
*
|
|
165
|
+
* Written to `agents/runtime/state/toolchain.json` by
|
|
166
|
+
* {@link write_config} so the per-stack commands are captured once and
|
|
167
|
+
* re-read cheaply (keyed on `mtime`) instead of re-detected every turn.
|
|
168
|
+
*/
|
|
169
|
+
to_config(): Record<string, unknown> {
|
|
170
|
+
return {
|
|
171
|
+
ecosystems: [...this.ecosystems],
|
|
172
|
+
confidence: this.confidence,
|
|
173
|
+
// `mtime` is a Python float; wrap so `write_config`'s serialiser
|
|
174
|
+
// renders an integral value as `N.0` (Python float repr).
|
|
175
|
+
mtime: pyFloat(this.mtime),
|
|
176
|
+
runners: this.runners.map((r) => ({
|
|
177
|
+
ecosystem: r.ecosystem,
|
|
178
|
+
runner: r.runner,
|
|
179
|
+
command: r.command,
|
|
180
|
+
speed: r.speed,
|
|
181
|
+
confidence: r.confidence,
|
|
182
|
+
basis: r.basis,
|
|
183
|
+
})),
|
|
184
|
+
selected: this.selected.map((r) => r.command),
|
|
185
|
+
quality: [...this.quality],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Inspect `project_root` and resolve its test/quality toolchain.
|
|
192
|
+
*
|
|
193
|
+
* @param project_root
|
|
194
|
+
* Directory carrying the manifests (`composer.json` / `package.json` /
|
|
195
|
+
* `pyproject.toml` / `go.mod` / `Cargo.toml`). The resolver does not walk
|
|
196
|
+
* upwards — the caller picks the scope, matching `detect.detect_stack`.
|
|
197
|
+
* @param opts.include_slow @param opts.include_e2e
|
|
198
|
+
* Monorepo guard. Off by default → `selected` carries only fast unit
|
|
199
|
+
* suites. Turn on to add the slow / e2e buckets.
|
|
200
|
+
* @param opts.php_only
|
|
201
|
+
* The `--php` narrowing — keep only the PHP ecosystem in `selected` (the
|
|
202
|
+
* full inventory is still returned in `runners`).
|
|
203
|
+
* @returns
|
|
204
|
+
* A {@link ToolchainResult}. Never raises. No manifest / unknown stack →
|
|
205
|
+
* an empty result with `confidence == LOW` so the caller can fall back to
|
|
206
|
+
* asking.
|
|
207
|
+
*/
|
|
208
|
+
export function resolve_toolchain(
|
|
209
|
+
project_root: string,
|
|
210
|
+
opts: { include_slow?: boolean; include_e2e?: boolean; php_only?: boolean } = {},
|
|
211
|
+
): ToolchainResult {
|
|
212
|
+
const include_slow = opts.include_slow ?? false;
|
|
213
|
+
const include_e2e = opts.include_e2e ?? false;
|
|
214
|
+
const php_only = opts.php_only ?? false;
|
|
215
|
+
|
|
216
|
+
const runners: RunnerResult[] = [];
|
|
217
|
+
const quality: string[] = [];
|
|
218
|
+
|
|
219
|
+
const composer = _read_json(path.join(project_root, 'composer.json'));
|
|
220
|
+
const pkg = _read_json(path.join(project_root, 'package.json'));
|
|
221
|
+
const has_composer = _is_file(path.join(project_root, 'composer.json'));
|
|
222
|
+
const has_package = _is_file(path.join(project_root, 'package.json'));
|
|
223
|
+
const pyproject_text = _read_text(path.join(project_root, 'pyproject.toml'));
|
|
224
|
+
const has_python =
|
|
225
|
+
Boolean(pyproject_text) ||
|
|
226
|
+
_is_file(path.join(project_root, 'requirements.txt')) ||
|
|
227
|
+
_is_file(path.join(project_root, 'setup.cfg')) ||
|
|
228
|
+
_is_file(path.join(project_root, 'pytest.ini'));
|
|
229
|
+
const has_go = _is_file(path.join(project_root, 'go.mod'));
|
|
230
|
+
const has_cargo = _is_file(path.join(project_root, 'Cargo.toml'));
|
|
231
|
+
|
|
232
|
+
const wrappers = _task_runner_wrappers(project_root, pkg);
|
|
233
|
+
|
|
234
|
+
if (has_composer) {
|
|
235
|
+
runners.push(..._php_runners(project_root, composer, wrappers));
|
|
236
|
+
quality.push(..._php_quality(project_root, composer, wrappers));
|
|
237
|
+
}
|
|
238
|
+
if (has_package) {
|
|
239
|
+
runners.push(..._js_runners(pkg, wrappers));
|
|
240
|
+
quality.push(..._js_quality(pkg, wrappers));
|
|
241
|
+
}
|
|
242
|
+
if (has_python) {
|
|
243
|
+
runners.push(..._python_runners(pyproject_text));
|
|
244
|
+
quality.push(..._python_quality(pyproject_text));
|
|
245
|
+
}
|
|
246
|
+
if (has_go) {
|
|
247
|
+
runners.push(
|
|
248
|
+
new RunnerResult('go', 'go-test', 'go test ./...', SPEED_FAST, HIGH, 'go.mod present'),
|
|
249
|
+
);
|
|
250
|
+
quality.push('go vet ./...');
|
|
251
|
+
}
|
|
252
|
+
if (has_cargo) {
|
|
253
|
+
runners.push(
|
|
254
|
+
new RunnerResult('rust', 'cargo-test', 'cargo test', SPEED_FAST, HIGH, 'Cargo.toml present'),
|
|
255
|
+
);
|
|
256
|
+
quality.push('cargo clippy');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const ecosystems = _dictFromKeys(runners.map((r) => r.ecosystem));
|
|
260
|
+
const selected = _apply_guard(runners, { include_slow, include_e2e, php_only });
|
|
261
|
+
const confidence = _overall_confidence(runners);
|
|
262
|
+
|
|
263
|
+
return new ToolchainResult({
|
|
264
|
+
ecosystems,
|
|
265
|
+
runners: [...runners],
|
|
266
|
+
selected: [...selected],
|
|
267
|
+
quality: _dictFromKeys(quality),
|
|
268
|
+
confidence,
|
|
269
|
+
mtime: latest_manifest_mtime(project_root),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Persist `result` to `agents/runtime/state/toolchain.json`.
|
|
275
|
+
*
|
|
276
|
+
* The auto-generated per-stack config the roadmap calls for. Best-effort:
|
|
277
|
+
* returns the path written; never raises on a read-only or missing parent
|
|
278
|
+
* (the resolver is a routing aid, not a hard dependency).
|
|
279
|
+
*/
|
|
280
|
+
export function write_config(project_root: string, result: ToolchainResult): string {
|
|
281
|
+
const target = path.join(project_root, 'agents', 'runtime', 'state', 'toolchain.json');
|
|
282
|
+
try {
|
|
283
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
284
|
+
fs.writeFileSync(
|
|
285
|
+
target,
|
|
286
|
+
jsonDumps(result.to_config(), { indent: 2, sort_keys: true }) + '\n',
|
|
287
|
+
{ encoding: 'utf-8' },
|
|
288
|
+
);
|
|
289
|
+
} catch {
|
|
290
|
+
// Mirrors Python's `except OSError: pass` — best-effort write.
|
|
291
|
+
}
|
|
292
|
+
return target;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Latest mtime across every manifest the resolver consults.
|
|
297
|
+
*
|
|
298
|
+
* Cache-invalidation hook: when the persisted value no longer matches the
|
|
299
|
+
* live value the cached toolchain is stale and resolution re-runs. `0.0`
|
|
300
|
+
* when no manifest exists (greenfield) — a stable sentinel, not a
|
|
301
|
+
* missing-file error.
|
|
302
|
+
*/
|
|
303
|
+
export function latest_manifest_mtime(project_root: string): number {
|
|
304
|
+
const mtimes: number[] = [];
|
|
305
|
+
for (const name of _MANIFESTS) {
|
|
306
|
+
const p = path.join(project_root, name);
|
|
307
|
+
if (_is_file(p)) {
|
|
308
|
+
mtimes.push(_stat_mtime(p));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return mtimes.length > 0 ? Math.max(...mtimes) : 0.0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// --------------------------------------------------------------------------
|
|
315
|
+
// Ecosystem resolvers
|
|
316
|
+
// --------------------------------------------------------------------------
|
|
317
|
+
|
|
318
|
+
function _php_runners(root: string, composer: Manifest, wrappers: Wrappers): RunnerResult[] {
|
|
319
|
+
const deps = _all_dependencies(composer, 'require', 'require-dev');
|
|
320
|
+
if ('pestphp/pest' in deps || _is_file(path.join(root, 'vendor', 'bin', 'pest'))) {
|
|
321
|
+
const cmd = wrappers['php-test'] || 'vendor/bin/pest';
|
|
322
|
+
const basis =
|
|
323
|
+
'pestphp/pest' in deps
|
|
324
|
+
? 'pestphp/pest in composer require'
|
|
325
|
+
: 'vendor/bin/pest present';
|
|
326
|
+
return [new RunnerResult('php', 'pest', cmd, SPEED_FAST, HIGH, basis)];
|
|
327
|
+
}
|
|
328
|
+
if (_is_file(path.join(root, 'artisan'))) {
|
|
329
|
+
const cmd = wrappers['php-test'] || 'php artisan test';
|
|
330
|
+
return [new RunnerResult('php', 'phpunit', cmd, SPEED_FAST, HIGH, 'artisan present (Laravel)')];
|
|
331
|
+
}
|
|
332
|
+
if ('phpunit/phpunit' in deps || _is_file(path.join(root, 'vendor', 'bin', 'phpunit'))) {
|
|
333
|
+
const cmd = wrappers['php-test'] || 'vendor/bin/phpunit';
|
|
334
|
+
return [new RunnerResult('php', 'phpunit', cmd, SPEED_FAST, HIGH, 'phpunit/phpunit detected')];
|
|
335
|
+
}
|
|
336
|
+
// composer.json with no test dependency — phpunit is the safe PHP default.
|
|
337
|
+
const cmd = wrappers['php-test'] || 'vendor/bin/phpunit';
|
|
338
|
+
return [
|
|
339
|
+
new RunnerResult(
|
|
340
|
+
'php',
|
|
341
|
+
'phpunit',
|
|
342
|
+
cmd,
|
|
343
|
+
SPEED_FAST,
|
|
344
|
+
MEDIUM,
|
|
345
|
+
'composer.json present, no explicit runner',
|
|
346
|
+
),
|
|
347
|
+
];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function _js_runners(pkg: Manifest, wrappers: Wrappers): RunnerResult[] {
|
|
351
|
+
const deps = _all_dependencies(
|
|
352
|
+
pkg,
|
|
353
|
+
'dependencies',
|
|
354
|
+
'devDependencies',
|
|
355
|
+
'peerDependencies',
|
|
356
|
+
'optionalDependencies',
|
|
357
|
+
);
|
|
358
|
+
const scripts: Manifest = _isDict(pkg.scripts) ? pkg.scripts : {};
|
|
359
|
+
const pm_test = wrappers['js-test'];
|
|
360
|
+
const out: RunnerResult[] = [];
|
|
361
|
+
|
|
362
|
+
// Fast unit runner — vitest beats jest when both present (vitest is the
|
|
363
|
+
// modern default), but only one fast runner is selected.
|
|
364
|
+
if ('vitest' in deps) {
|
|
365
|
+
const cmd =
|
|
366
|
+
pm_test && _script_uses(scripts, 'test', 'vitest') ? pm_test : 'npx vitest run';
|
|
367
|
+
out.push(new RunnerResult('js', 'vitest', cmd, SPEED_FAST, HIGH, 'vitest in package deps'));
|
|
368
|
+
} else if ('jest' in deps) {
|
|
369
|
+
const cmd = pm_test && _script_uses(scripts, 'test', 'jest') ? pm_test : 'npx jest';
|
|
370
|
+
out.push(new RunnerResult('js', 'jest', cmd, SPEED_FAST, HIGH, 'jest in package deps'));
|
|
371
|
+
} else if (pm_test) {
|
|
372
|
+
out.push(
|
|
373
|
+
new RunnerResult(
|
|
374
|
+
'js',
|
|
375
|
+
'jest',
|
|
376
|
+
pm_test,
|
|
377
|
+
SPEED_FAST,
|
|
378
|
+
MEDIUM,
|
|
379
|
+
'package.json test script, runner unclear',
|
|
380
|
+
),
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// e2e runner — separate bucket, excluded unless --include-e2e.
|
|
385
|
+
if ('@playwright/test' in deps || 'playwright' in deps) {
|
|
386
|
+
const cmd = _script_command(scripts, ['test:e2e', 'e2e', 'playwright']) || 'npx playwright test';
|
|
387
|
+
out.push(
|
|
388
|
+
new RunnerResult('js', 'playwright', cmd, SPEED_E2E, HIGH, '@playwright/test in package deps'),
|
|
389
|
+
);
|
|
390
|
+
} else if ('cypress' in deps) {
|
|
391
|
+
const cmd = _script_command(scripts, ['test:e2e', 'e2e', 'cypress']) || 'npx cypress run';
|
|
392
|
+
out.push(new RunnerResult('js', 'cypress', cmd, SPEED_E2E, HIGH, 'cypress in package deps'));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// slow bucket — an explicit slow/integration script.
|
|
396
|
+
const slow_cmd = _script_command(scripts, ['test:slow', 'test:integration']);
|
|
397
|
+
if (slow_cmd) {
|
|
398
|
+
out.push(
|
|
399
|
+
new RunnerResult(
|
|
400
|
+
'js',
|
|
401
|
+
'vitest' in deps ? 'vitest' : 'jest',
|
|
402
|
+
slow_cmd,
|
|
403
|
+
SPEED_SLOW,
|
|
404
|
+
MEDIUM,
|
|
405
|
+
'test:slow/integration script',
|
|
406
|
+
),
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
return out;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function _python_runners(pyproject_text: string): RunnerResult[] {
|
|
413
|
+
if (pyproject_text.includes('pytest') || pyproject_text === '') {
|
|
414
|
+
const conf = pyproject_text.includes('pytest') ? HIGH : MEDIUM;
|
|
415
|
+
const basis = pyproject_text.includes('pytest')
|
|
416
|
+
? 'pytest in pyproject'
|
|
417
|
+
: 'python project, no explicit runner';
|
|
418
|
+
return [new RunnerResult('python', 'pytest', 'pytest', SPEED_FAST, conf, basis)];
|
|
419
|
+
}
|
|
420
|
+
return [
|
|
421
|
+
new RunnerResult('python', 'pytest', 'pytest', SPEED_FAST, MEDIUM, 'python project, no explicit runner'),
|
|
422
|
+
];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function _php_quality(root: string, composer: Manifest, _wrappers: Wrappers): string[] {
|
|
426
|
+
const deps = _all_dependencies(composer, 'require', 'require-dev');
|
|
427
|
+
const out: string[] = [];
|
|
428
|
+
if ('phpstan/phpstan' in deps || _is_file(path.join(root, 'vendor', 'bin', 'phpstan'))) {
|
|
429
|
+
out.push('vendor/bin/phpstan analyse');
|
|
430
|
+
}
|
|
431
|
+
if ('laravel/pint' in deps || _is_file(path.join(root, 'vendor', 'bin', 'pint'))) {
|
|
432
|
+
out.push('vendor/bin/pint');
|
|
433
|
+
}
|
|
434
|
+
return out;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function _js_quality(pkg: Manifest, _wrappers: Wrappers): string[] {
|
|
438
|
+
const deps = _all_dependencies(
|
|
439
|
+
pkg,
|
|
440
|
+
'dependencies',
|
|
441
|
+
'devDependencies',
|
|
442
|
+
'peerDependencies',
|
|
443
|
+
'optionalDependencies',
|
|
444
|
+
);
|
|
445
|
+
const out: string[] = [];
|
|
446
|
+
if ('typescript' in deps) {
|
|
447
|
+
out.push('npx tsc --noEmit');
|
|
448
|
+
}
|
|
449
|
+
if ('eslint' in deps) {
|
|
450
|
+
out.push('npx eslint .');
|
|
451
|
+
}
|
|
452
|
+
return out;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function _python_quality(pyproject_text: string): string[] {
|
|
456
|
+
const out: string[] = [];
|
|
457
|
+
if (pyproject_text.includes('ruff')) {
|
|
458
|
+
out.push('ruff check');
|
|
459
|
+
}
|
|
460
|
+
if (pyproject_text.includes('mypy')) {
|
|
461
|
+
out.push('mypy .');
|
|
462
|
+
}
|
|
463
|
+
return out;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// --------------------------------------------------------------------------
|
|
467
|
+
// Task-runner wrappers (Makefile / Taskfile / package scripts)
|
|
468
|
+
// --------------------------------------------------------------------------
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Map logical roles to a wrapper command when one exists.
|
|
472
|
+
*
|
|
473
|
+
* Wrappers win over direct tool invocation (they handle container access,
|
|
474
|
+
* env, parallelism) — the architecture rule's "Build / Task Runner
|
|
475
|
+
* Detection". Returns role → command; absent roles fall through to the
|
|
476
|
+
* direct tool.
|
|
477
|
+
*/
|
|
478
|
+
function _task_runner_wrappers(root: string, pkg: Manifest): Wrappers {
|
|
479
|
+
const out: Wrappers = {};
|
|
480
|
+
const makefile = _read_text(path.join(root, 'Makefile'));
|
|
481
|
+
const taskfile =
|
|
482
|
+
_read_text(path.join(root, 'Taskfile.yml')) || _read_text(path.join(root, 'Taskfile.yaml'));
|
|
483
|
+
if (makefile && _reSearch(/^test\s*:/m, makefile)) {
|
|
484
|
+
out['php-test'] = 'make test';
|
|
485
|
+
} else if (taskfile && _reSearch(/^\s*test\s*:/m, taskfile)) {
|
|
486
|
+
out['php-test'] = 'task test';
|
|
487
|
+
}
|
|
488
|
+
const scripts: Manifest = _isDict(pkg.scripts) ? pkg.scripts : {};
|
|
489
|
+
if (_isDict(scripts) && 'test' in scripts) {
|
|
490
|
+
out['js-test'] = `${_package_manager(root)} test`;
|
|
491
|
+
}
|
|
492
|
+
return out;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function _package_manager(root: string): string {
|
|
496
|
+
if (_is_file(path.join(root, 'pnpm-lock.yaml'))) {
|
|
497
|
+
return 'pnpm';
|
|
498
|
+
}
|
|
499
|
+
if (_is_file(path.join(root, 'yarn.lock'))) {
|
|
500
|
+
return 'yarn';
|
|
501
|
+
}
|
|
502
|
+
return 'npm';
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// --------------------------------------------------------------------------
|
|
506
|
+
// Monorepo guard + confidence
|
|
507
|
+
// --------------------------------------------------------------------------
|
|
508
|
+
|
|
509
|
+
function _apply_guard(
|
|
510
|
+
runners: RunnerResult[],
|
|
511
|
+
opts: { include_slow: boolean; include_e2e: boolean; php_only: boolean },
|
|
512
|
+
): RunnerResult[] {
|
|
513
|
+
const out: RunnerResult[] = [];
|
|
514
|
+
for (const r of runners) {
|
|
515
|
+
if (opts.php_only && r.ecosystem !== 'php') {
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
if (r.speed === SPEED_E2E && !opts.include_e2e) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
if (r.speed === SPEED_SLOW && !opts.include_slow) {
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
out.push(r);
|
|
525
|
+
}
|
|
526
|
+
return out;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function _overall_confidence(runners: RunnerResult[]): string {
|
|
530
|
+
if (runners.length === 0) {
|
|
531
|
+
return LOW;
|
|
532
|
+
}
|
|
533
|
+
if (runners.some((r) => r.confidence === HIGH)) {
|
|
534
|
+
return HIGH;
|
|
535
|
+
}
|
|
536
|
+
return MEDIUM;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// --------------------------------------------------------------------------
|
|
540
|
+
// Shared readers (mirror detect.py's recoverable-error contract)
|
|
541
|
+
// --------------------------------------------------------------------------
|
|
542
|
+
|
|
543
|
+
function _read_json(p: string): Manifest {
|
|
544
|
+
if (!_is_file(p)) {
|
|
545
|
+
return {};
|
|
546
|
+
}
|
|
547
|
+
let payload: unknown;
|
|
548
|
+
try {
|
|
549
|
+
payload = JSON.parse(fs.readFileSync(p, { encoding: 'utf-8' }));
|
|
550
|
+
} catch {
|
|
551
|
+
return {};
|
|
552
|
+
}
|
|
553
|
+
return _isDict(payload) ? payload : {};
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function _read_text(p: string): string {
|
|
557
|
+
if (!_is_file(p)) {
|
|
558
|
+
return '';
|
|
559
|
+
}
|
|
560
|
+
try {
|
|
561
|
+
return fs.readFileSync(p, { encoding: 'utf-8' });
|
|
562
|
+
} catch {
|
|
563
|
+
return '';
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function _all_dependencies(manifest: Manifest, ...keys: string[]): Manifest {
|
|
568
|
+
const merged: Manifest = {};
|
|
569
|
+
for (const key of keys) {
|
|
570
|
+
const section = manifest[key];
|
|
571
|
+
if (_isDict(section)) {
|
|
572
|
+
Object.assign(merged, section);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return merged;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function _script_uses(scripts: Manifest, name: string, tool: string): boolean {
|
|
579
|
+
const value = scripts[name];
|
|
580
|
+
return typeof value === 'string' && value.includes(tool);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function _script_command(scripts: Manifest, names: string[]): string {
|
|
584
|
+
for (const name of names) {
|
|
585
|
+
if (typeof scripts[name] === 'string') {
|
|
586
|
+
return `npm run ${name}`;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return '';
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// --------------------------------------------------------------------------
|
|
593
|
+
// stdlib parity helpers
|
|
594
|
+
// --------------------------------------------------------------------------
|
|
595
|
+
|
|
596
|
+
/** Python `Path.is_file()` — true only for a regular file (follows symlinks). */
|
|
597
|
+
function _is_file(p: string): boolean {
|
|
598
|
+
try {
|
|
599
|
+
return fs.statSync(p).isFile();
|
|
600
|
+
} catch {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Python `Path.stat().st_mtime` in POSIX seconds — see the matching note in
|
|
607
|
+
* `detect.ts`. Only `to_config` / `write_config` serialize this value, and
|
|
608
|
+
* the parity tests treat the serialized `mtime` as non-deterministic.
|
|
609
|
+
*/
|
|
610
|
+
function _stat_mtime(p: string): number {
|
|
611
|
+
const st = fs.statSync(p, { bigint: true });
|
|
612
|
+
return Number(st.mtimeNs) / 1e9;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/** Python `isinstance(x, dict)` — a plain (non-array, non-null) object. */
|
|
616
|
+
function _isDict(v: unknown): v is Manifest {
|
|
617
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Python `re.search(pattern, text)` truthiness. The patterns used here carry
|
|
622
|
+
* the multiline flag (`(?m)` in the source → `/m` here), so `^`/`$` match at
|
|
623
|
+
* line boundaries exactly like CPython's `re`.
|
|
624
|
+
*/
|
|
625
|
+
function _reSearch(pattern: RegExp, text: string): boolean {
|
|
626
|
+
return pattern.test(text);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Python `tuple(dict.fromkeys(seq))` — dedupe preserving first-seen insertion
|
|
631
|
+
* order. `dict.fromkeys` keeps the first occurrence's position; a JS `Set`
|
|
632
|
+
* built by iteration does the same, so `[...new Set(seq)]` is faithful.
|
|
633
|
+
*/
|
|
634
|
+
function _dictFromKeys(seq: string[]): string[] {
|
|
635
|
+
return [...new Set(seq)];
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// --------------------------------------------------------------------------
|
|
639
|
+
// JSON serialisation — byte-parity with `json.dumps(..., indent=2,
|
|
640
|
+
// sort_keys=True)` for `write_config`.
|
|
641
|
+
// --------------------------------------------------------------------------
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Mirror Python `json.dumps(obj, indent=2, sort_keys=True)` byte-for-byte.
|
|
645
|
+
*
|
|
646
|
+
* Two CPython behaviours that `JSON.stringify` does NOT reproduce on its own
|
|
647
|
+
* and are reproduced here:
|
|
648
|
+
*
|
|
649
|
+
* - `sort_keys=True` — object keys emitted in code-point ascending order.
|
|
650
|
+
* `JSON.stringify` preserves insertion order; we pre-sort recursively.
|
|
651
|
+
* - integer-valued floats render as `N.0` (e.g. `1767222000.0`). JSON has no
|
|
652
|
+
* float/int tag, so a JS `number` that is integral renders without `.0`.
|
|
653
|
+
* In this module the only float is `mtime`; the parity tests normalize it
|
|
654
|
+
* (its exact byte-repr is not reproducible across CPython/V8), but the
|
|
655
|
+
* serialiser still applies the `N.0` rule via a tagged float wrapper so the
|
|
656
|
+
* *shape* matches. `mtime` is the sole value passed through that wrapper.
|
|
657
|
+
*
|
|
658
|
+
* 2-space indent, `": "` key separator, `","` item separator with the
|
|
659
|
+
* indent-driven newline, `{}` / `[]` for empties, non-ASCII verbatim
|
|
660
|
+
* (`ensure_ascii` defaults to `True` in CPython, but `to_config` carries no
|
|
661
|
+
* non-ASCII, so the distinction never surfaces).
|
|
662
|
+
*/
|
|
663
|
+
function jsonDumps(obj: unknown, opts: { indent: number; sort_keys: boolean }): string {
|
|
664
|
+
return _encode(obj, opts, 0);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const _INDENT_UNIT = ' ';
|
|
668
|
+
|
|
669
|
+
function _encode(value: unknown, opts: { indent: number; sort_keys: boolean }, depth: number): string {
|
|
670
|
+
if (value === null) {
|
|
671
|
+
return 'null';
|
|
672
|
+
}
|
|
673
|
+
if (typeof value === 'boolean') {
|
|
674
|
+
return value ? 'true' : 'false';
|
|
675
|
+
}
|
|
676
|
+
if (typeof value === 'number') {
|
|
677
|
+
return _encodeNumber(value, false);
|
|
678
|
+
}
|
|
679
|
+
if (value instanceof _PyFloat) {
|
|
680
|
+
return _encodeNumber(value.value, true);
|
|
681
|
+
}
|
|
682
|
+
if (typeof value === 'string') {
|
|
683
|
+
return JSON.stringify(value);
|
|
684
|
+
}
|
|
685
|
+
if (Array.isArray(value)) {
|
|
686
|
+
if (value.length === 0) {
|
|
687
|
+
return '[]';
|
|
688
|
+
}
|
|
689
|
+
const inner = _INDENT_UNIT.repeat(opts.indent * (depth + 1));
|
|
690
|
+
const items = value.map((v) => inner + _encode(v, opts, depth + 1));
|
|
691
|
+
const close = _INDENT_UNIT.repeat(opts.indent * depth);
|
|
692
|
+
return '[\n' + items.join(',\n') + '\n' + close + ']';
|
|
693
|
+
}
|
|
694
|
+
if (_isDict(value)) {
|
|
695
|
+
let keys = Object.keys(value);
|
|
696
|
+
if (keys.length === 0) {
|
|
697
|
+
return '{}';
|
|
698
|
+
}
|
|
699
|
+
if (opts.sort_keys) {
|
|
700
|
+
keys = keys.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
701
|
+
}
|
|
702
|
+
const inner = _INDENT_UNIT.repeat(opts.indent * (depth + 1));
|
|
703
|
+
const items = keys.map(
|
|
704
|
+
(k) => inner + JSON.stringify(k) + ': ' + _encode(value[k], opts, depth + 1),
|
|
705
|
+
);
|
|
706
|
+
const close = _INDENT_UNIT.repeat(opts.indent * depth);
|
|
707
|
+
return '{\n' + items.join(',\n') + '\n' + close + '}';
|
|
708
|
+
}
|
|
709
|
+
// Unreachable for `to_config` output; mirror `json.dumps` raising on an
|
|
710
|
+
// unserialisable type would require a TypeError — return the JS default.
|
|
711
|
+
return JSON.stringify(value);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Render a number like CPython's `float.__repr__` / `int.__repr__` inside
|
|
716
|
+
* `json.dumps`. When `isFloat` is set and the value is integral, append
|
|
717
|
+
* `.0` (Python's float repr). Non-integral floats use JS's shortest
|
|
718
|
+
* round-trip repr — which matches CPython's `repr(float)` for the values
|
|
719
|
+
* that arise here. (The `mtime` field is normalized by the parity tests, so
|
|
720
|
+
* any residual last-digit divergence on exotic sub-second timestamps is not
|
|
721
|
+
* load-bearing.)
|
|
722
|
+
*/
|
|
723
|
+
function _encodeNumber(n: number, isFloat: boolean): string {
|
|
724
|
+
if (isFloat && Number.isInteger(n)) {
|
|
725
|
+
return `${n}.0`;
|
|
726
|
+
}
|
|
727
|
+
return String(n);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/** Tag wrapper marking a JS number that must serialise with Python float repr. */
|
|
731
|
+
class _PyFloat {
|
|
732
|
+
readonly value: number;
|
|
733
|
+
constructor(value: number) {
|
|
734
|
+
this.value = value;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Wrap a numeric value so {@link jsonDumps} renders it as a Python float
|
|
740
|
+
* (integer-valued → `N.0`). Exported for the parity tests / callers that
|
|
741
|
+
* round-trip a `ToolchainResult` through `to_config`.
|
|
742
|
+
*/
|
|
743
|
+
export function pyFloat(value: number): _PyFloat {
|
|
744
|
+
return new _PyFloat(value);
|
|
745
|
+
}
|