@event4u/agent-config 16.1.0 → 16.3.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 +98 -257
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +5 -5
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/commands/work.md +4 -0
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
- package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-review/SKILL.md +30 -4
- package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
- package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +30 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/dist/cli/python/knowledge_ingest.js +1 -1
- package/dist/cli/python/workspace_drive.js +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
- package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1862 -809
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +132 -80
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +7972 -5186
- package/dist/hooks/dispatch.sha256 +1 -0
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2226 -1055
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +40913 -34865
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +29 -0
- package/dist/shared/skillRanking.js +74 -13
- package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
- package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
- package/dist/ui/index.html +2 -2
- package/docs/contracts/settings-classes.md +10 -6
- package/package.json +4 -4
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
- package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
- package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
- package/src/config/agent-settings.template.yml +91 -22
- package/src/config/ci-local-parity.yml +18 -0
- package/src/config/continuity-surface.json +9 -2
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +327 -3
- package/src/config/gate-violation-baselines.json +21 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-latency-budget.json +21 -0
- package/src/config/hook-token-budget.json +8 -3
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/metric-registry.yml +114 -0
- package/src/config/placeholder-drift-budget.json +10 -0
- package/src/config/routing-coverage-seed.json +38 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +28 -90
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_cli/doctor_execution.ts +100 -17
- package/src/scripts/_cli/doctor_network_posture.ts +226 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/body_portable.ts +102 -0
- package/src/scripts/_lib/cc_transcript.ts +132 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/concern_sla_window.ts +200 -0
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/forge_protection.ts +114 -0
- package/src/scripts/_lib/forge_reader.ts +558 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_env_write.ts +111 -0
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/obligations.ts +119 -8
- package/src/scripts/_lib/probe_inputs.ts +271 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/read_surface_scan.ts +322 -0
- package/src/scripts/_lib/release_highlights.ts +2 -1
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/shell_write_shapes.ts +108 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structural_hiding.ts +622 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +600 -4
- package/src/scripts/_lib/turn_end_transcript.ts +216 -0
- package/src/scripts/_lib/verification_command.ts +324 -0
- package/src/scripts/_lib/verification_evidence.ts +647 -0
- package/src/scripts/_lib/verify_clause.ts +280 -0
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/team_dispatch.ts +4 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +573 -25
- package/src/scripts/bench_hook_latency.ts +412 -5
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/cache_realization_report.ts +61 -1
- package/src/scripts/check_argument_hint.ts +287 -0
- package/src/scripts/check_claims.ts +125 -1
- package/src/scripts/check_enforcement_coverage.ts +38 -9
- package/src/scripts/check_enforcement_matrix.ts +621 -22
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +138 -7
- package/src/scripts/check_generator_sync.ts +71 -0
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_host_docs_digest.ts +786 -0
- package/src/scripts/check_host_format_column.ts +559 -0
- package/src/scripts/check_input_references.ts +228 -0
- package/src/scripts/check_inputs_parity.ts +235 -0
- package/src/scripts/check_kernel_edit_ratified.ts +89 -9
- package/src/scripts/check_kill_switch_table.ts +294 -0
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_placeholder_drift.ts +221 -0
- package/src/scripts/check_read_surface_coverage.ts +515 -0
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_holds.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_routing_coverage.ts +378 -11
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_static_parity.ts +17 -0
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +145 -19
- package/src/scripts/closure_scan.ts +115 -1
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +90 -14
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/external_sources_denylist.json +29 -4
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +192 -14
- package/src/scripts/hooks/block_config_weakening.ts +294 -4
- package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
- package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
- package/src/scripts/hooks/bundle_integrity.ts +291 -0
- package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
- package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
- package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/concern_timings.ts +94 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
- package/src/scripts/hooks/design_pass_hook.ts +100 -9
- package/src/scripts/hooks/design_slop_hook.ts +1 -2
- package/src/scripts/hooks/dispatch_hook.ts +77 -71
- package/src/scripts/hooks/edit_shape_hook.ts +1 -2
- package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
- package/src/scripts/hooks/evidence_independence.ts +1 -2
- package/src/scripts/hooks/exit_codes.ts +129 -0
- package/src/scripts/hooks/host_lowering.json +1 -0
- package/src/scripts/hooks/host_lowering.ts +146 -3
- package/src/scripts/hooks/host_lowering.yaml +262 -46
- package/src/scripts/hooks/host_semantics.ts +30 -2
- package/src/scripts/hooks/injection_budget.ts +9 -2
- package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
- package/src/scripts/hooks/journal_record_hook.ts +1 -2
- package/src/scripts/hooks/memory_recall_hook.ts +1 -2
- package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
- package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
- package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/permission_gate.ts +1 -2
- package/src/scripts/hooks/push_settle_hook.ts +1 -3
- package/src/scripts/hooks/replay_hook.ts +2 -1
- package/src/scripts/hooks/reread_guard_hook.ts +1 -2
- package/src/scripts/hooks/review_baseline_hook.ts +1 -2
- package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
- package/src/scripts/hooks/rule_inject_hook.ts +765 -68
- package/src/scripts/hooks/run_continuation_hook.ts +13 -15
- package/src/scripts/hooks/skill_route_hook.ts +1 -2
- package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
- package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
- package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
- package/src/scripts/hooks/table_fingerprint.ts +70 -0
- package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
- package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
- package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
- package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
- package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +75 -189
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_deny_text.ts +419 -0
- package/src/scripts/lint_exit_codes.ts +262 -0
- package/src/scripts/lint_hook_manifest.ts +108 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_roadmap_blockers.ts +78 -12
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_skill_descriptions.ts +1 -1
- package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/mcp_server/prompts.ts +142 -1
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
- package/src/scripts/measure_turn_end_gate.ts +193 -0
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/memory_lookup.ts +1 -1
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/prepack-check.mjs +53 -0
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/release_publication.ts +13 -1
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_invocation_surface.ts +383 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_carriers.ts +699 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_obligation_writer_split.ts +236 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_menu_census.ts +208 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/roadmap_verify_share.ts +213 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/command.schema.json +44 -0
- package/src/scripts/schemas/review-findings.schema.json +7 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +44 -0
- package/src/scripts/self_review_gate.ts +421 -17
- package/src/scripts/semantic_parity_census.ts +314 -0
- package/src/scripts/session_eol_report.ts +54 -1
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_dead_scan_roots.ts +1 -1
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -7
- package/src/scripts/trigger_eval_rotation.ts +122 -27
- package/src/scripts/ui_conformance_probe.ts +156 -4
- package/src/scripts/update_prices.ts +85 -3
- package/src/scripts/write_bundle_digest.mjs +74 -0
- package/src/server/schemas/settings.ts +41 -0
- package/src/shared/skillRanking.ts +117 -11
- package/src/templates/consumer-settings/ONBOARDING.md +1 -0
- package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
- package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/dist/ui/assets/index-DH1xc62v.js +0 -29
- package/dist/ui/assets/index-jSfMW8_t.css +0 -1
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* touched_file_quality — run the project's OWN quality commands, in shadow,
|
|
3
|
+
* over the files a turn actually edited.
|
|
4
|
+
*
|
|
5
|
+
* loss_class: ephemeral-lossy
|
|
6
|
+
*
|
|
7
|
+
* The one place this module shortens content is `advisoryLine`, whose 200-byte
|
|
8
|
+
* cap (roadmap 2.2) trims a summary it synthesised itself from `QualityRun[]`.
|
|
9
|
+
* The trimmed tail is not stored anywhere and is not meant to be: the runs are
|
|
10
|
+
* in-memory for one invocation, the line goes to stderr, and the verdict it
|
|
11
|
+
* summarises is reproduced by re-running the same resolver command. A recovery
|
|
12
|
+
* locator would promise a retrieval nothing performs.
|
|
13
|
+
*
|
|
14
|
+
* `road-to-touched-files-that-pass-their-own-tools` Phase 1. The project already
|
|
15
|
+
* computes a per-stack quality list — `resolve_toolchain().quality` in
|
|
16
|
+
* `src/agent-src/templates/scripts/work_engine/stack/runner.ts` — and nothing at
|
|
17
|
+
* stop calls it. This module is the caller. It owns no list of its own: D2 of the
|
|
18
|
+
* roadmap pins the resolver as the single authority, because a second list is a
|
|
19
|
+
* second authority that drifts from the first in silence.
|
|
20
|
+
*
|
|
21
|
+
* WHAT THIS IS NOT. It is not verification. A command recorded here never reaches
|
|
22
|
+
* `_lib/verification_command.ts`, never raises `verifications_this_turn`, and
|
|
23
|
+
* never sets `verified_this_turn` — `eslint` exits 0 over a clean file set, and a
|
|
24
|
+
* zero exit that reached the completion gate would mean a turn could claim "I
|
|
25
|
+
* verified" by having edited nothing interesting. The producer writes
|
|
26
|
+
* `quality_runs[]`; the classifier reads `verification_runs[]`. Two arrays, two
|
|
27
|
+
* readers, no overlap — pinned by a negative fixture rather than by this comment.
|
|
28
|
+
*
|
|
29
|
+
* FOUR RULES, AND EACH ONE EXISTS BECAUSE THE NAIVE VERSION IS HARMFUL.
|
|
30
|
+
*
|
|
31
|
+
* 1. A command runs only if the resolver listed it. Nothing is synthesised.
|
|
32
|
+
* 2. A command that WRITES runs only in its check form, or not at all. The
|
|
33
|
+
* resolver emits `vendor/bin/pint`, which rewrites the consumer's source; a
|
|
34
|
+
* shadow pass that reformats the tree it is observing is not a shadow pass.
|
|
35
|
+
* Where a check flag is known (`--test`) it is used; where it is not, the row
|
|
36
|
+
* is `skipped: mutating` and the command is never spawned.
|
|
37
|
+
* 3. A command with no file-scoped form is `skipped: unscoped`. `tsc --noEmit`
|
|
38
|
+
* cannot take a file list without discarding `tsconfig.json`, and running it
|
|
39
|
+
* project-wide at every stop makes stop the slowest hook in the chain. The
|
|
40
|
+
* resolver carries no cost field, so nothing here guesses that an unknown
|
|
41
|
+
* command is cheap: an unrecognised command is `unscoped` and is not run.
|
|
42
|
+
* 4. ENOENT or exit 127 is `skipped: absent`, counted apart from verdicts.
|
|
43
|
+
* Detection upstream is by manifest (`typescript` in `devDependencies`), not
|
|
44
|
+
* by presence on PATH, so "the tool is not installed" must never read as a red.
|
|
45
|
+
*
|
|
46
|
+
* Output per command: the command, its exit code, and the first 20 lines of its
|
|
47
|
+
* combined output. Bounded on purpose — this lands in a per-session state file
|
|
48
|
+
* that another hook reads on every turn.
|
|
49
|
+
*/
|
|
50
|
+
import { spawnSync } from 'node:child_process';
|
|
51
|
+
import * as fs from 'node:fs';
|
|
52
|
+
import * as path from 'node:path';
|
|
53
|
+
|
|
54
|
+
/** Lines of combined output retained per command. */
|
|
55
|
+
export const OUTPUT_HEAD_LINES = 20;
|
|
56
|
+
|
|
57
|
+
/** Default per-command wall-clock bound, milliseconds. */
|
|
58
|
+
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Why a command was not executed.
|
|
62
|
+
*
|
|
63
|
+
* `no_files` is the fourth reason and is not in the roadmap's prose list, which
|
|
64
|
+
* named three. It is needed and it is honest: running `eslint` over a turn that
|
|
65
|
+
* touched only `.php` files produces a verdict about nothing. 2.1 counts
|
|
66
|
+
* `skipped:*` separately from verdicts, and the glob is what makes a fourth
|
|
67
|
+
* reason additive rather than a contract change.
|
|
68
|
+
*/
|
|
69
|
+
export type SkipReason = 'mutating' | 'unscoped' | 'absent' | 'no_files';
|
|
70
|
+
|
|
71
|
+
/** One resolver command, classified into a runnable form or a skip reason. */
|
|
72
|
+
export interface QualityPlan {
|
|
73
|
+
/** The resolver's command string, verbatim — the provenance of this row. */
|
|
74
|
+
readonly source_command: string;
|
|
75
|
+
/** argv actually spawned, or `null` when the row is skipped. */
|
|
76
|
+
readonly argv: readonly string[] | null;
|
|
77
|
+
/** The touched files passed to it. */
|
|
78
|
+
readonly files: readonly string[];
|
|
79
|
+
readonly skipped: SkipReason | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One executed (or deliberately skipped) quality command. */
|
|
83
|
+
export interface QualityRun {
|
|
84
|
+
/** The command as run, or the resolver's command when skipped. */
|
|
85
|
+
readonly command: string;
|
|
86
|
+
readonly source_command: string;
|
|
87
|
+
/** `null` when the row was skipped — never `0`, which is a real verdict. */
|
|
88
|
+
readonly exit_code: number | null;
|
|
89
|
+
readonly output_head: readonly string[];
|
|
90
|
+
readonly skipped: SkipReason | null;
|
|
91
|
+
readonly files: readonly string[];
|
|
92
|
+
readonly at: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* How one resolver command is turned into a file-scoped, non-writing form.
|
|
97
|
+
*
|
|
98
|
+
* Keyed on the exact string the resolver emits. Keying on the whole command
|
|
99
|
+
* rather than on a parsed head is deliberate: the key IS the resolver's output,
|
|
100
|
+
* so a resolver change that this table has not seen falls through to `unscoped`
|
|
101
|
+
* and is not run, instead of being half-recognised and run in a form nobody
|
|
102
|
+
* chose.
|
|
103
|
+
*/
|
|
104
|
+
interface ToolSpec {
|
|
105
|
+
/** argv prefix; the touched files are appended. */
|
|
106
|
+
readonly argv: readonly string[];
|
|
107
|
+
/** Extensions this tool reads. Empty means "any file". */
|
|
108
|
+
readonly extensions: readonly string[];
|
|
109
|
+
/**
|
|
110
|
+
* The resolver's own command writes files, and `argv` above is its check
|
|
111
|
+
* form. Recorded so a reader can see that the executed command differs from
|
|
112
|
+
* the resolver's by exactly the flag that makes it read-only.
|
|
113
|
+
*/
|
|
114
|
+
readonly check_form: boolean;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const JS_EXTENSIONS = ['.js', '.jsx', '.mjs', '.cjs', '.ts', '.tsx', '.mts', '.cts'] as const;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* The scoped forms, one row per resolver command that HAS one.
|
|
121
|
+
*
|
|
122
|
+
* Everything the resolver can emit that is absent here — `npx tsc --noEmit`,
|
|
123
|
+
* `go vet ./...`, `cargo clippy` — is absent because it has no per-file form,
|
|
124
|
+
* and absence is what produces `skipped: unscoped`.
|
|
125
|
+
*/
|
|
126
|
+
const SCOPED_FORMS: ReadonlyMap<string, ToolSpec> = new Map<string, ToolSpec>([
|
|
127
|
+
['npx eslint .', { argv: ['npx', 'eslint'], extensions: JS_EXTENSIONS, check_form: false }],
|
|
128
|
+
[
|
|
129
|
+
'vendor/bin/phpstan analyse',
|
|
130
|
+
{ argv: ['vendor/bin/phpstan', 'analyse'], extensions: ['.php'], check_form: false },
|
|
131
|
+
],
|
|
132
|
+
// `vendor/bin/pint` REWRITES source. `--test` is its check form: same tool,
|
|
133
|
+
// same rules, reports instead of writing. Risk 3 of the roadmap is that this
|
|
134
|
+
// module reformats the consumer's tree; this row plus the fixture that proves
|
|
135
|
+
// no file changed is the mitigation.
|
|
136
|
+
[
|
|
137
|
+
'vendor/bin/pint',
|
|
138
|
+
{ argv: ['vendor/bin/pint', '--test'], extensions: ['.php'], check_form: true },
|
|
139
|
+
],
|
|
140
|
+
['ruff check', { argv: ['ruff', 'check'], extensions: ['.py'], check_form: false }],
|
|
141
|
+
['mypy .', { argv: ['mypy'], extensions: ['.py'], check_form: false }],
|
|
142
|
+
]);
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Resolver commands known to write files for which NO check form is known.
|
|
146
|
+
*
|
|
147
|
+
* Empty today — every mutating command the resolver emits (`vendor/bin/pint`)
|
|
148
|
+
* has one, and it is in `SCOPED_FORMS` above. The map exists so that the day a
|
|
149
|
+
* writing command without a `--check` lands, the answer is a row here
|
|
150
|
+
* (`skipped: mutating`, never spawned) rather than a judgement call at the call
|
|
151
|
+
* site. A mutating command that fell through to `unscoped` would be recorded
|
|
152
|
+
* under the wrong reason and counted in the wrong bucket by 2.1.
|
|
153
|
+
*/
|
|
154
|
+
const MUTATING_WITHOUT_CHECK_FORM: ReadonlySet<string> = new Set<string>([]);
|
|
155
|
+
|
|
156
|
+
function extensionOf(file: string): string {
|
|
157
|
+
const base = path.basename(file);
|
|
158
|
+
const dot = base.lastIndexOf('.');
|
|
159
|
+
return dot <= 0 ? '' : base.slice(dot).toLowerCase();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Classify the resolver's list against the turn's touched files. PURE.
|
|
164
|
+
*
|
|
165
|
+
* Separated from execution so the four rules above are testable without
|
|
166
|
+
* spawning anything, and so a reader can see the whole policy in one return
|
|
167
|
+
* value before any process starts.
|
|
168
|
+
*/
|
|
169
|
+
export function planQualityRuns(
|
|
170
|
+
commands: readonly string[],
|
|
171
|
+
files: readonly string[],
|
|
172
|
+
): QualityPlan[] {
|
|
173
|
+
return commands.map((source_command): QualityPlan => {
|
|
174
|
+
if (MUTATING_WITHOUT_CHECK_FORM.has(source_command)) {
|
|
175
|
+
return { source_command, argv: null, files: [], skipped: 'mutating' };
|
|
176
|
+
}
|
|
177
|
+
const spec = SCOPED_FORMS.get(source_command);
|
|
178
|
+
if (spec === undefined) {
|
|
179
|
+
return { source_command, argv: null, files: [], skipped: 'unscoped' };
|
|
180
|
+
}
|
|
181
|
+
const matched =
|
|
182
|
+
spec.extensions.length === 0
|
|
183
|
+
? [...files]
|
|
184
|
+
: files.filter((f) => spec.extensions.includes(extensionOf(f)));
|
|
185
|
+
if (matched.length === 0) {
|
|
186
|
+
return { source_command, argv: null, files: [], skipped: 'no_files' };
|
|
187
|
+
}
|
|
188
|
+
return { source_command, argv: [...spec.argv, ...matched], files: matched, skipped: null };
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** `argv` rendered for the record. Not re-parsed — display and audit only. */
|
|
193
|
+
export function renderCommand(argv: readonly string[]): string {
|
|
194
|
+
return argv.join(' ');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function headLines(text: string, limit: number): string[] {
|
|
198
|
+
if (text === '') return [];
|
|
199
|
+
return text
|
|
200
|
+
.split(/\r\n|\r|\n/)
|
|
201
|
+
.filter((line, i, all) => !(line === '' && i === all.length - 1))
|
|
202
|
+
.slice(0, limit);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** ISO-8601 to seconds, matching the record's other timestamps. */
|
|
206
|
+
function now(): string {
|
|
207
|
+
return new Date().toISOString().replace(/\.\d{3}Z$/, '+00:00');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface RunOptions {
|
|
211
|
+
readonly root: string;
|
|
212
|
+
readonly commands: readonly string[];
|
|
213
|
+
readonly files: readonly string[];
|
|
214
|
+
readonly timeout_ms?: number;
|
|
215
|
+
/** Injected in tests so the table's behaviour is observable without a toolchain. */
|
|
216
|
+
readonly spawn?: (
|
|
217
|
+
argv: readonly string[],
|
|
218
|
+
cwd: string,
|
|
219
|
+
timeout_ms: number,
|
|
220
|
+
) => { status: number | null; output: string; enoent: boolean };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function defaultSpawn(
|
|
224
|
+
argv: readonly string[],
|
|
225
|
+
cwd: string,
|
|
226
|
+
timeout_ms: number,
|
|
227
|
+
): { status: number | null; output: string; enoent: boolean } {
|
|
228
|
+
const [head, ...rest] = argv;
|
|
229
|
+
if (head === undefined) return { status: null, output: '', enoent: true };
|
|
230
|
+
const res = spawnSync(head, rest, {
|
|
231
|
+
cwd,
|
|
232
|
+
timeout: timeout_ms,
|
|
233
|
+
encoding: 'utf-8',
|
|
234
|
+
// No shell. The argv comes from a committed table, and a shell would
|
|
235
|
+
// make a file path with a space into an injection surface.
|
|
236
|
+
shell: false,
|
|
237
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
238
|
+
});
|
|
239
|
+
const enoent =
|
|
240
|
+
res.error !== undefined &&
|
|
241
|
+
(res.error as NodeJS.ErrnoException).code === 'ENOENT';
|
|
242
|
+
const output = `${res.stdout ?? ''}${res.stderr ?? ''}`;
|
|
243
|
+
return { status: res.status, output, enoent };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Execute the plan and return one record per resolver command.
|
|
248
|
+
*
|
|
249
|
+
* Never throws. A spawn that fails for any reason becomes a row, because a
|
|
250
|
+
* shadow pass that can take the stop hook down with it is worse than no shadow
|
|
251
|
+
* pass at all.
|
|
252
|
+
*/
|
|
253
|
+
export function runTouchedFileQuality(opts: RunOptions): QualityRun[] {
|
|
254
|
+
const timeout_ms = opts.timeout_ms ?? DEFAULT_TIMEOUT_MS;
|
|
255
|
+
const spawn = opts.spawn ?? defaultSpawn;
|
|
256
|
+
const out: QualityRun[] = [];
|
|
257
|
+
for (const plan of planQualityRuns(opts.commands, opts.files)) {
|
|
258
|
+
if (plan.argv === null) {
|
|
259
|
+
out.push({
|
|
260
|
+
command: plan.source_command,
|
|
261
|
+
source_command: plan.source_command,
|
|
262
|
+
exit_code: null,
|
|
263
|
+
output_head: [],
|
|
264
|
+
skipped: plan.skipped,
|
|
265
|
+
files: [],
|
|
266
|
+
at: now(),
|
|
267
|
+
});
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
let status: number | null = null;
|
|
271
|
+
let output = '';
|
|
272
|
+
let enoent = false;
|
|
273
|
+
try {
|
|
274
|
+
const res = spawn(plan.argv, opts.root, timeout_ms);
|
|
275
|
+
status = res.status;
|
|
276
|
+
output = res.output;
|
|
277
|
+
enoent = res.enoent;
|
|
278
|
+
} catch {
|
|
279
|
+
enoent = true;
|
|
280
|
+
}
|
|
281
|
+
// Exit 127 is the shell's "command not found" and reaches us when the
|
|
282
|
+
// tool is a wrapper script whose own dependency is missing. Same meaning
|
|
283
|
+
// as ENOENT for this module's purposes, and the same bucket in 2.1.
|
|
284
|
+
const absent = enoent || status === 127;
|
|
285
|
+
out.push({
|
|
286
|
+
command: renderCommand(plan.argv),
|
|
287
|
+
source_command: plan.source_command,
|
|
288
|
+
exit_code: absent ? null : status,
|
|
289
|
+
output_head: absent ? [] : headLines(output, OUTPUT_HEAD_LINES),
|
|
290
|
+
skipped: absent ? 'absent' : null,
|
|
291
|
+
files: plan.files,
|
|
292
|
+
at: now(),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
return out;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* The single advisory line `warn` mode emits — command, first file, verdict.
|
|
300
|
+
*
|
|
301
|
+
* `null` when nothing failed. Capped at 200 bytes by the roadmap's 2.2, and the
|
|
302
|
+
* cap is enforced on the UTF-8 byte length rather than on `String.length`, which
|
|
303
|
+
* counts code units and would let a path with non-ASCII characters through at
|
|
304
|
+
* nearly twice the budget.
|
|
305
|
+
*/
|
|
306
|
+
export const WARN_LINE_MAX_BYTES = 200;
|
|
307
|
+
|
|
308
|
+
export function advisoryLine(runs: readonly QualityRun[]): string | null {
|
|
309
|
+
const failed = runs.find((r) => r.skipped === null && r.exit_code !== null && r.exit_code !== 0);
|
|
310
|
+
if (failed === undefined) return null;
|
|
311
|
+
const file = failed.files[0] ?? '(no file)';
|
|
312
|
+
const more = failed.files.length > 1 ? ` (+${String(failed.files.length - 1)} more)` : '';
|
|
313
|
+
const line = `touched-file quality: ${failed.source_command} exited ${String(failed.exit_code)} on ${file}${more}`;
|
|
314
|
+
return truncateToBytes(line, WARN_LINE_MAX_BYTES);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Cut `text` so its UTF-8 encoding is at most `max` bytes, never mid-character. */
|
|
318
|
+
export function truncateToBytes(text: string, max: number): string {
|
|
319
|
+
const buf = Buffer.from(text, 'utf-8');
|
|
320
|
+
if (buf.length <= max) return text;
|
|
321
|
+
let end = max;
|
|
322
|
+
// Back off into the start of a character: continuation bytes are 10xxxxxx.
|
|
323
|
+
while (end > 0 && (buf[end] ?? 0) >= 0x80 && (buf[end] ?? 0) < 0xc0) end -= 1;
|
|
324
|
+
return buf.subarray(0, end).toString('utf-8');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
// Which files the turn touched
|
|
329
|
+
// ---------------------------------------------------------------------------
|
|
330
|
+
|
|
331
|
+
/** Where the touched-path set came from, recorded beside the runs. */
|
|
332
|
+
export type FileSource = 'minimal-safe-diff∩worktree' | 'none';
|
|
333
|
+
|
|
334
|
+
export interface TouchedFiles {
|
|
335
|
+
readonly files: readonly string[];
|
|
336
|
+
readonly source: FileSource;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* The turn's touched files, intersected with what the working tree says changed.
|
|
341
|
+
*
|
|
342
|
+
* RISK 4 OF THE ROADMAP, AND THE REASON THIS IS NOT JUST A READ.
|
|
343
|
+
* `agents/state/minimal-safe-diff.json` is ONE FILE PER PROJECT ROOT, not per
|
|
344
|
+
* session — and under this repository's worktree workflow `CLAUDE_PROJECT_DIR`
|
|
345
|
+
* resolves to the parent checkout, so concurrent runs share it. Reading it
|
|
346
|
+
* straight would let a neighbouring session's edits become this session's
|
|
347
|
+
* quality target.
|
|
348
|
+
*
|
|
349
|
+
* Two independent narrowings, and both are needed:
|
|
350
|
+
*
|
|
351
|
+
* - OWNERSHIP. A state file whose `session_id` is not this session's is
|
|
352
|
+
* refused outright, which is the same stance `owns_session_state` takes on
|
|
353
|
+
* the verification record.
|
|
354
|
+
* - THE WORKING TREE. A path is kept only if git still reports it as changed.
|
|
355
|
+
* A path the recorder saw but the tree has since reverted is not a quality
|
|
356
|
+
* target, and an edit from a different checkout is not in THIS tree's status.
|
|
357
|
+
*
|
|
358
|
+
* An absent, foreign or unreadable recorder state yields `none` and NO files,
|
|
359
|
+
* which makes the shadow pass a no-op. The alternative — falling back to the
|
|
360
|
+
* whole working tree — is exactly the cross-session leak this is guarding, so
|
|
361
|
+
* the degradation is toward measuring nothing rather than toward measuring
|
|
362
|
+
* somebody else's work.
|
|
363
|
+
*/
|
|
364
|
+
export function touchedFilesAtStop(
|
|
365
|
+
root: string,
|
|
366
|
+
session_id: string,
|
|
367
|
+
gitStatus: (root: string) => readonly string[] = defaultGitStatus,
|
|
368
|
+
): TouchedFiles {
|
|
369
|
+
let recorded: string[];
|
|
370
|
+
try {
|
|
371
|
+
const raw = fs.readFileSync(
|
|
372
|
+
path.join(root, 'agents', 'state', 'minimal-safe-diff.json'),
|
|
373
|
+
'utf-8',
|
|
374
|
+
);
|
|
375
|
+
const decoded: unknown = JSON.parse(raw);
|
|
376
|
+
if (typeof decoded !== 'object' || decoded === null || Array.isArray(decoded)) {
|
|
377
|
+
return { files: [], source: 'none' };
|
|
378
|
+
}
|
|
379
|
+
const state = decoded as Record<string, unknown>;
|
|
380
|
+
if (state['session_id'] !== session_id || session_id === '') {
|
|
381
|
+
return { files: [], source: 'none' };
|
|
382
|
+
}
|
|
383
|
+
const touched = state['files_touched_this_turn'];
|
|
384
|
+
if (!Array.isArray(touched)) return { files: [], source: 'none' };
|
|
385
|
+
recorded = touched.filter((x): x is string => typeof x === 'string');
|
|
386
|
+
} catch {
|
|
387
|
+
return { files: [], source: 'none' };
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const changed = new Set(gitStatus(root));
|
|
391
|
+
const files = recorded.filter((f) => changed.has(normalizePath(f)));
|
|
392
|
+
return { files, source: 'minimal-safe-diff∩worktree' };
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** Repo-relative, forward slashes, no leading `./` — the shape git prints. */
|
|
396
|
+
export function normalizePath(p: string): string {
|
|
397
|
+
return p.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function defaultGitStatus(root: string): string[] {
|
|
401
|
+
const res = spawnSync('git', ['status', '--porcelain', '-z'], {
|
|
402
|
+
cwd: root,
|
|
403
|
+
encoding: 'utf-8',
|
|
404
|
+
timeout: 10_000,
|
|
405
|
+
shell: false,
|
|
406
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
407
|
+
});
|
|
408
|
+
if (res.status !== 0 || typeof res.stdout !== 'string') return [];
|
|
409
|
+
return parsePorcelainZ(res.stdout);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Paths out of `git status --porcelain -z`.
|
|
414
|
+
*
|
|
415
|
+
* `-z` rather than the line-oriented form: without it git QUOTES a path holding
|
|
416
|
+
* a space or a non-ASCII byte, and the quoted form never matches a recorded
|
|
417
|
+
* path, so the intersection would silently drop exactly the files most likely
|
|
418
|
+
* to be mis-handled downstream. A rename entry carries two NUL-separated paths
|
|
419
|
+
* (`R <new>\0<old>`); the new path is the one that exists to be checked.
|
|
420
|
+
*/
|
|
421
|
+
export function parsePorcelainZ(stdout: string): string[] {
|
|
422
|
+
const out: string[] = [];
|
|
423
|
+
const parts = stdout.split('\0');
|
|
424
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
425
|
+
const entry = parts[i];
|
|
426
|
+
if (entry === undefined || entry.length < 4) continue;
|
|
427
|
+
const status = entry.slice(0, 2);
|
|
428
|
+
out.push(normalizePath(entry.slice(3)));
|
|
429
|
+
// Rename / copy: the NEXT NUL-separated field is the ORIGIN path, which
|
|
430
|
+
// is consumed here so it is not read as a status entry of its own.
|
|
431
|
+
if (status.startsWith('R') || status.startsWith('C')) i += 1;
|
|
432
|
+
}
|
|
433
|
+
return out;
|
|
434
|
+
}
|