@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,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agent-config doctor neighbours` — render the neighbour census.
|
|
3
|
+
*
|
|
4
|
+
* A separate entry point rather than another branch inside `cmd_doctor.ts`,
|
|
5
|
+
* which sits 2,000 lines above the source-size ceiling: a verb this size does
|
|
6
|
+
* not belong in a file that already cannot grow. The census itself is
|
|
7
|
+
* `_lib/neighbour_census.ts`; everything here is presentation and the one
|
|
8
|
+
* summary line the full `doctor` run links to.
|
|
9
|
+
*
|
|
10
|
+
* Refuses nothing. No label here removes, blocks, or rewrites a neighbour's
|
|
11
|
+
* artifact — a label is a report, never a gate.
|
|
12
|
+
*
|
|
13
|
+
* It is no longer read-ONLY, and the two writes are named rather than implied.
|
|
14
|
+
* Both land under `agents/reports/` and both are caches of this run's own
|
|
15
|
+
* findings: `neighbour-scan.json`, the shape-scan verdicts the ranker reads on
|
|
16
|
+
* the hook path, and `neighbour-overlap.json`, the cross-root pairs keyed by the
|
|
17
|
+
* census digest. Nothing outside that directory is touched, and a failed write
|
|
18
|
+
* is not a failed census.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import * as fs from 'node:fs';
|
|
22
|
+
import * as path from 'node:path';
|
|
23
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
24
|
+
|
|
25
|
+
import * as YAML from 'yaml';
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
census,
|
|
29
|
+
fileDigest,
|
|
30
|
+
gatedEventsFrom,
|
|
31
|
+
scanCachePath,
|
|
32
|
+
type NeighbourCensus,
|
|
33
|
+
} from '../_lib/neighbour_census.js';
|
|
34
|
+
import { scanNeighbourBody, writeScanCache } from '../_lib/neighbour_scan.js';
|
|
35
|
+
import { resolvePackageRoot } from '../_lib/package_root.js';
|
|
36
|
+
import {
|
|
37
|
+
OVERLAP_THRESHOLD,
|
|
38
|
+
CROSS_CACHE_NAME,
|
|
39
|
+
cachedCrossRootPairs,
|
|
40
|
+
crossRootOverlapMap,
|
|
41
|
+
} from '../audit_skill_overlap.js';
|
|
42
|
+
|
|
43
|
+
interface ManifestShape {
|
|
44
|
+
concerns?: Record<string, { effect?: string }>;
|
|
45
|
+
platforms?: Record<string, Record<string, unknown>>;
|
|
46
|
+
native_event_aliases?: Record<string, Record<string, string>>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Read the hook manifest for the events a `permission` concern of ours sits on. */
|
|
50
|
+
function gatedEvents(packageRoot: string): Set<string> {
|
|
51
|
+
try {
|
|
52
|
+
// A missing or unreadable manifest yields an empty gate set, which
|
|
53
|
+
// downgrades `degraded` to `coordinated` rather than inventing a gate
|
|
54
|
+
// that is not there.
|
|
55
|
+
const file = path.join(packageRoot, 'src', 'scripts', 'hook_manifest.yaml');
|
|
56
|
+
const doc = YAML.parse(fs.readFileSync(file, 'utf-8')) as ManifestShape;
|
|
57
|
+
return gatedEventsFrom(doc, doc.native_event_aliases ?? {});
|
|
58
|
+
} catch {
|
|
59
|
+
return new Set<string>();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** This package's own skill names, for the `shadowed` warning. */
|
|
64
|
+
function ourSkillNames(packageRoot: string): Set<string> {
|
|
65
|
+
try {
|
|
66
|
+
return new Set(
|
|
67
|
+
fs
|
|
68
|
+
.readdirSync(path.join(packageRoot, 'src', 'skills'), { withFileTypes: true })
|
|
69
|
+
.filter((e) => e.isDirectory())
|
|
70
|
+
.map((e) => e.name),
|
|
71
|
+
);
|
|
72
|
+
} catch {
|
|
73
|
+
return new Set<string>();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The census, in two passes, and the second one is not an accident.
|
|
79
|
+
*
|
|
80
|
+
* The cross-root overlap can only be computed over the neighbour skills the
|
|
81
|
+
* census FOUND — the unclaimed entries of two roots that also hold claimed ones,
|
|
82
|
+
* since `agent-config install` writes this package's own skills into
|
|
83
|
+
* `~/.claude/skills`. Pairing whole roots instead would compare our installed
|
|
84
|
+
* copies against our own source tree and publish the install as an overlap. So
|
|
85
|
+
* pass one finds them, the overlap runs over exactly those files, and pass two
|
|
86
|
+
* labels them.
|
|
87
|
+
*
|
|
88
|
+
* The shape scan is memoized across both passes, so the four linters run once
|
|
89
|
+
* per neighbour body rather than twice. The scan verdicts are then WRITTEN to
|
|
90
|
+
* the cache the ranker reads on the hook path — this verb is the only producer,
|
|
91
|
+
* which is why its absence reads there as `no-scan-record` rather than as a pass.
|
|
92
|
+
*/
|
|
93
|
+
export function runCensus(
|
|
94
|
+
projectRoot: string,
|
|
95
|
+
packageRoot: string,
|
|
96
|
+
homeRoot?: string,
|
|
97
|
+
): NeighbourCensus {
|
|
98
|
+
const scanned = new Map<string, string | null>();
|
|
99
|
+
const scan = (p: string): string | null => {
|
|
100
|
+
const hit = scanned.get(p);
|
|
101
|
+
if (hit !== undefined) return hit;
|
|
102
|
+
const kind = scanNeighbourBody(p).kind;
|
|
103
|
+
scanned.set(p, kind);
|
|
104
|
+
return kind;
|
|
105
|
+
};
|
|
106
|
+
const base = {
|
|
107
|
+
gatedEvents: gatedEvents(packageRoot),
|
|
108
|
+
templatesRoot: path.join(packageRoot, 'src', 'agent-src', 'templates'),
|
|
109
|
+
ourSkillNames: ourSkillNames(packageRoot),
|
|
110
|
+
packageRoot,
|
|
111
|
+
scan,
|
|
112
|
+
...(homeRoot === undefined ? {} : { homeRoot }),
|
|
113
|
+
};
|
|
114
|
+
const first = census(projectRoot, base);
|
|
115
|
+
const ourRoot = path.join(packageRoot, 'src', 'skills');
|
|
116
|
+
let overlaps = new Map<string, { names: string[]; similarity: number }>();
|
|
117
|
+
if (first.skills.length > 0 && fs.existsSync(ourRoot)) {
|
|
118
|
+
try {
|
|
119
|
+
const { pairs } = cachedCrossRootPairs(
|
|
120
|
+
first.skills.map((s) => s.source),
|
|
121
|
+
ourRoot,
|
|
122
|
+
path.join(projectRoot, 'agents', 'reports', CROSS_CACHE_NAME),
|
|
123
|
+
OVERLAP_THRESHOLD,
|
|
124
|
+
);
|
|
125
|
+
overlaps = crossRootOverlapMap(pairs);
|
|
126
|
+
} catch {
|
|
127
|
+
// An overlap pass that cannot run leaves every entry unlabelled by
|
|
128
|
+
// it, which reads as `unclassified` — the absence of a signal — and
|
|
129
|
+
// never as a claim that the pair is disjoint.
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const full = census(projectRoot, { ...base, overlaps });
|
|
133
|
+
writeScanCache(
|
|
134
|
+
scanCachePath(projectRoot),
|
|
135
|
+
// `fileDigest`, not the census's own `digest`: the ranker re-digests the
|
|
136
|
+
// file bytes it is about to index, and a cache written under a different
|
|
137
|
+
// digest function would read as `digest-changed` on every prompt.
|
|
138
|
+
full.skills.map((s) => ({
|
|
139
|
+
qualified: s.qualified,
|
|
140
|
+
digest: fileDigest(s.source) ?? '',
|
|
141
|
+
unscanned: s.unscanned,
|
|
142
|
+
})),
|
|
143
|
+
);
|
|
144
|
+
return full;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** The one line the full `doctor` run prints, linking to this verb. */
|
|
148
|
+
export function summaryLine(c: NeighbourCensus): string {
|
|
149
|
+
const counts = [
|
|
150
|
+
`${c.hook_groups.length} hook group(s)`,
|
|
151
|
+
`${c.skills.length} skill(s)`,
|
|
152
|
+
`${c.commands.length} command(s)`,
|
|
153
|
+
`${c.agents.length} agent(s)`,
|
|
154
|
+
`${c.mcp_servers.length} mcp server(s)`,
|
|
155
|
+
`${c.rule_files.length} rule file(s)`,
|
|
156
|
+
`${c.instruction_sections.length} instruction section(s)`,
|
|
157
|
+
].join(', ');
|
|
158
|
+
const labels = c.hosts.map((h) => `${h.host}=${h.label}`).join(' ');
|
|
159
|
+
return ` 🏘️ neighbours: ${counts}${labels === '' ? '' : ` · ${labels}`} (run \`doctor neighbours\` for the census)`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function renderText(c: NeighbourCensus): string[] {
|
|
163
|
+
const out: string[] = [];
|
|
164
|
+
out.push(` 📍 project_root: ${c.project_root}`);
|
|
165
|
+
out.push('');
|
|
166
|
+
for (const h of c.hosts) {
|
|
167
|
+
out.push(` ${h.host}: ${h.label} — ${h.label_reason}`);
|
|
168
|
+
for (const e of h.hook_groups) {
|
|
169
|
+
const matcher = e.matcher === null ? '' : ` matcher=${e.matcher}`;
|
|
170
|
+
const timeout = e.timeout === null ? '' : ` timeout=${e.timeout}`;
|
|
171
|
+
out.push(` ${e.event}: ${e.command_head}${matcher}${timeout} effect=${e.effect}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const section = (title: string, rows: ReadonlyArray<{ id: string }>): void => {
|
|
175
|
+
if (rows.length === 0) return;
|
|
176
|
+
out.push('');
|
|
177
|
+
out.push(` ${title} (${rows.length})`);
|
|
178
|
+
for (const r of rows) out.push(` ${r.id}`);
|
|
179
|
+
};
|
|
180
|
+
if (c.skills.length > 0) {
|
|
181
|
+
out.push('');
|
|
182
|
+
out.push(` skills (${c.skills.length})`);
|
|
183
|
+
for (const s of c.skills) {
|
|
184
|
+
const also = s.also.length === 0 ? '' : ` also: ${s.also.join(', ')}`;
|
|
185
|
+
const why = s.unscanned === null ? '' : ` unscanned: ${s.unscanned}`;
|
|
186
|
+
out.push(` ${s.qualified} compat: ${s.compat}${also}${why}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
section('commands', c.commands);
|
|
190
|
+
section('agents', c.agents);
|
|
191
|
+
if (c.mcp_servers.length > 0) {
|
|
192
|
+
out.push('');
|
|
193
|
+
out.push(` mcp servers (${c.mcp_servers.length})`);
|
|
194
|
+
for (const m of c.mcp_servers) {
|
|
195
|
+
// `used` and `advertised` are printed side by side so the reader
|
|
196
|
+
// never takes the first for a coverage ratio: the denominator is
|
|
197
|
+
// not missing by accident, it is not obtainable without launching
|
|
198
|
+
// the neighbour's process, which this census does not do.
|
|
199
|
+
out.push(
|
|
200
|
+
` ${m.id} tools used (${m.tools_window_days}d): ${m.tools_used_30d}` +
|
|
201
|
+
` advertised: ${m.tools_advertised}`,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
section('rule files', c.rule_files);
|
|
206
|
+
section('instruction sections', c.instruction_sections);
|
|
207
|
+
if (c.warnings.length > 0) {
|
|
208
|
+
out.push('');
|
|
209
|
+
for (const w of c.warnings) out.push(` ⚠️ ${w.kind}: ${w.detail}`);
|
|
210
|
+
}
|
|
211
|
+
out.push('');
|
|
212
|
+
out.push(
|
|
213
|
+
' The host owns load order. This census says what is there and what each entry would do;',
|
|
214
|
+
);
|
|
215
|
+
out.push(' it cannot say what ran first, and no label here refuses anything.');
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
220
|
+
let json = false;
|
|
221
|
+
let root = process.cwd();
|
|
222
|
+
let home: string | undefined;
|
|
223
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
224
|
+
if (argv[i] === '--json') json = true;
|
|
225
|
+
else if (argv[i] === '--project') {
|
|
226
|
+
root = argv[i + 1] ?? root;
|
|
227
|
+
i += 1;
|
|
228
|
+
} else if (argv[i] === '--home') {
|
|
229
|
+
// Fixture-only: the user-scope half of the census is real `$HOME`
|
|
230
|
+
// in production, and a test must be able to plant one.
|
|
231
|
+
home = argv[i + 1];
|
|
232
|
+
i += 1;
|
|
233
|
+
} else if (argv[i] === 'neighbours') {
|
|
234
|
+
continue;
|
|
235
|
+
} else {
|
|
236
|
+
process.stderr.write(`doctor neighbours: unknown argument: ${argv[i]}\n`);
|
|
237
|
+
return 2;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const c = runCensus(path.resolve(root), resolvePackageRoot(import.meta.url), home);
|
|
241
|
+
if (json) {
|
|
242
|
+
// Compact, not pretty-printed: this is the machine contract, and the
|
|
243
|
+
// gate that reads it matches on adjacency rather than on indentation.
|
|
244
|
+
process.stdout.write(`${JSON.stringify(c)}\n`);
|
|
245
|
+
} else {
|
|
246
|
+
for (const line of renderText(c)) process.stdout.write(`${line}\n`);
|
|
247
|
+
}
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Same entry guard the sibling CLIs use — including the delegate branch, which
|
|
253
|
+
* an earlier version of this file left out and which the delegate smoke test
|
|
254
|
+
* caught: `no bundle is a silent no-op` reported `cmd_doctor_neighbours.js (no
|
|
255
|
+
* output, exit 0)`, the exact shape the paragraph below describes.
|
|
256
|
+
*
|
|
257
|
+
* Inside the cli-delegate bundle `--splitting` moves this module's body into a
|
|
258
|
+
* shared chunk, so the URL comparison weighs the CHUNK against `argv[1]` and
|
|
259
|
+
* never matches. `agent-config doctor` shipped that way once already — a
|
|
260
|
+
* diagnostic reporting success while saying nothing. The invoked file name is
|
|
261
|
+
* the reliable signal there; a miss falls THROUGH to the realpath comparison
|
|
262
|
+
* rather than returning false, so a symlinked or renamed invocation still
|
|
263
|
+
* resolves. Inlined into the installer / hook / MCP bundle instead, it must
|
|
264
|
+
* never auto-run, which is why one "am I bundled" flag cannot answer "may I
|
|
265
|
+
* run" and both flags are read.
|
|
266
|
+
*/
|
|
267
|
+
declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
|
|
268
|
+
declare const __AGENT_CONFIG_CLI_DELEGATE__: boolean | undefined;
|
|
269
|
+
|
|
270
|
+
function _isCliEntry(): boolean {
|
|
271
|
+
const bundled = typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__;
|
|
272
|
+
const cliDelegate =
|
|
273
|
+
typeof __AGENT_CONFIG_CLI_DELEGATE__ !== 'undefined' && __AGENT_CONFIG_CLI_DELEGATE__;
|
|
274
|
+
if (bundled && !cliDelegate) return false;
|
|
275
|
+
if (process.argv[1] === undefined) return false;
|
|
276
|
+
if (cliDelegate && path.basename(process.argv[1], '.js') === 'cmd_doctor_neighbours') {
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
280
|
+
if (import.meta.url === argvUrl) return true;
|
|
281
|
+
try {
|
|
282
|
+
return (
|
|
283
|
+
fs.realpathSync(fileURLToPath(import.meta.url)) ===
|
|
284
|
+
fs.realpathSync(path.resolve(process.argv[1]))
|
|
285
|
+
);
|
|
286
|
+
} catch {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (_isCliEntry()) {
|
|
292
|
+
process.exit(main());
|
|
293
|
+
}
|
|
@@ -23,6 +23,15 @@ import {
|
|
|
23
23
|
protectionActions,
|
|
24
24
|
type ForgeReading,
|
|
25
25
|
} from '../_lib/forge_protection.js';
|
|
26
|
+
import {
|
|
27
|
+
FORGE_TOTAL_BUDGET_MS,
|
|
28
|
+
budgetOf,
|
|
29
|
+
forgeReadingFor,
|
|
30
|
+
liveForgeApi,
|
|
31
|
+
originUrl,
|
|
32
|
+
resolveForgeRepo,
|
|
33
|
+
type Runner,
|
|
34
|
+
} from '../_lib/forge_reader.js';
|
|
26
35
|
|
|
27
36
|
type Dict = Record<string, unknown>;
|
|
28
37
|
|
|
@@ -52,12 +61,17 @@ export function executionJson(overrides: () => OverrideStream): Dict {
|
|
|
52
61
|
/**
|
|
53
62
|
* The `forge_protection` block of `doctor --json` — Phase 3.2.
|
|
54
63
|
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
64
|
+
* **THIS function does not reach the network; `doctor` now does.** The mapper
|
|
65
|
+
* stays pure and takes an INJECTED reading — a caller that queried the forge
|
|
66
|
+
* passes it, one that did not passes the all-null reading, which produces five
|
|
67
|
+
* `unread` rows that still name the call each value would come from. What
|
|
68
|
+
* changed is the caller: `forgeProtectionJsonFor` below acquires that reading,
|
|
69
|
+
* so `doctor --json` does make `gh` calls. Phase 3.2's "`doctor` does not reach
|
|
70
|
+
* the network" is SUPERSEDED, and this header said otherwise for three review
|
|
71
|
+
* rounds while the function forty lines down called it a reversal — the third
|
|
72
|
+
* copy of a refuted argument in this diff, each found by a different round.
|
|
73
|
+
* Corrected here for the reason the others were: a header is where a dead
|
|
74
|
+
* argument gets reused.
|
|
61
75
|
*
|
|
62
76
|
* That is the honest shape for *read, never guessed*: the block is always
|
|
63
77
|
* present, a value appears only when a named call produced it, and `unread` is a
|
|
@@ -67,24 +81,93 @@ export function executionJson(overrides: () => OverrideStream): Dict {
|
|
|
67
81
|
* `actions` carries the human ACTION lines — the step's own words are that a
|
|
68
82
|
* missing row is a blocker entry and NOT a halt, so this reports and returns.
|
|
69
83
|
*/
|
|
70
|
-
export function forgeProtectionJson(reading: ForgeReading): Dict {
|
|
84
|
+
export function forgeProtectionJson(reading: ForgeReading, repo: string | null = null): Dict {
|
|
71
85
|
const rows = forgeProtectionRows(reading);
|
|
86
|
+
const readFromForge = rows.some((r) => r.state !== 'unread');
|
|
87
|
+
// **The slug is reported only when something was actually read, and that
|
|
88
|
+
// invariant is structural rather than a caller's promise.** The first
|
|
89
|
+
// version reported whatever the git remote resolved to, which is a LOCAL
|
|
90
|
+
// read that succeeds with no network — so an ordinary offline run (GitHub
|
|
91
|
+
// remote present, no connectivity, no opt-out) emitted a named repository
|
|
92
|
+
// and substituted sources while every row was `unread`. That made the
|
|
93
|
+
// claim this change rests on — offline output is what Phase 3.2 shipped —
|
|
94
|
+
// false on exactly the failed-live path the council condition names. The
|
|
95
|
+
// earlier verification only ever exercised the opt-out switch and read it
|
|
96
|
+
// as offline; the two are not the same path.
|
|
97
|
+
const anonymous = repo === null || !readFromForge;
|
|
98
|
+
const name = (s: string): string =>
|
|
99
|
+
anonymous ? s : s.replace(/\{owner\}\/\{repo\}/g, () => repo);
|
|
72
100
|
return {
|
|
101
|
+
repository: readFromForge ? repo : null,
|
|
73
102
|
rows: rows.map((r) => ({
|
|
74
103
|
id: r.id,
|
|
75
104
|
state: r.state,
|
|
76
|
-
source: r.source,
|
|
105
|
+
source: name(r.source),
|
|
77
106
|
detail: r.detail,
|
|
78
107
|
})),
|
|
79
|
-
actions: protectionActions(rows),
|
|
80
|
-
read_from_forge:
|
|
108
|
+
actions: protectionActions(rows).map(name),
|
|
109
|
+
read_from_forge: readFromForge,
|
|
81
110
|
};
|
|
82
111
|
}
|
|
83
112
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
113
|
+
/**
|
|
114
|
+
* The block as `doctor` itself builds it — AC-5.
|
|
115
|
+
*
|
|
116
|
+
* Phase 3.2 left `forgeProtectionJson` with no production caller, so the
|
|
117
|
+
* command the criterion names reported five `unread` rows while the forge
|
|
118
|
+
* satisfied all five, and the rows were only ever established by a human
|
|
119
|
+
* running `gh api` and reading the mapper in a test. This is the wiring that
|
|
120
|
+
* makes the named command answer for itself.
|
|
121
|
+
*
|
|
122
|
+
* **This IS a reversal of Phase 3.2's module boundary, and the roadmap records
|
|
123
|
+
* the supersession.** An earlier draft of this comment argued the opposite —
|
|
124
|
+
* "an addition rather than a reversal" — which a 2/2 convergent council pass
|
|
125
|
+
* refuted: that note recorded two boundaries, `doctor` does not reach the
|
|
126
|
+
* network AND the reading is injected, and this reverses both. The refuted
|
|
127
|
+
* argument is corrected here rather than left standing, because a comment is
|
|
128
|
+
* what the next reader of this module finds first and is where a refuted
|
|
129
|
+
* reasoning would get reused.
|
|
130
|
+
*
|
|
131
|
+
* What survives is the AVAILABILITY property, which is narrower than the
|
|
132
|
+
* earlier claim and is the one the supersession rests on: every failure path in
|
|
133
|
+
* `forgeReadingFor` — opt-out switch, no GitHub remote, no `gh`, no
|
|
134
|
+
* credentials, timeout, unparseable payload, a throw — returns the same
|
|
135
|
+
* `UNREAD_FORGE` reading, so offline the ROWS, their `source` templates and the
|
|
136
|
+
* action lines are what Phase 3.2 printed. Not the whole document: the block
|
|
137
|
+
* gained a top-level `repository` key, which is `null` on every such path. A
|
|
138
|
+
* consumer validating `forge_protection` against a closed schema sees that one
|
|
139
|
+
* added key; "prints exactly what it printed before" was too strong and is not
|
|
140
|
+
* claimed.
|
|
141
|
+
*
|
|
142
|
+
* `process.env` and the git remote are read HERE rather than inside the reader,
|
|
143
|
+
* so the reader stays injectable and every branch above is reachable from a
|
|
144
|
+
* test without spawning anything.
|
|
145
|
+
*/
|
|
146
|
+
export interface ForgeDeps {
|
|
147
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
148
|
+
/** The subprocess runner for both `git` and `gh`. */
|
|
149
|
+
readonly run?: Runner;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function forgeProtectionJsonFor(root: string, deps: ForgeDeps = {}): Dict {
|
|
153
|
+
// The composition root — budget, thunk, host and cwd wired together — had
|
|
154
|
+
// no seam and therefore no test, so the opt-out-before-spawn and host
|
|
155
|
+
// binding were asserted one layer down against fakes while a regression in
|
|
156
|
+
// the real wiring stayed invisible. `deps` is that seam; production passes
|
|
157
|
+
// nothing and gets `process.env` plus the real spawn.
|
|
158
|
+
const env = deps.env ?? process.env;
|
|
159
|
+
const run = deps.run;
|
|
160
|
+
const remaining = budgetOf(FORGE_TOTAL_BUDGET_MS);
|
|
161
|
+
const read = forgeReadingFor({
|
|
162
|
+
env,
|
|
163
|
+
// A thunk, so the opt-out short-circuits before `git` spawns.
|
|
164
|
+
resolveRepo: () => resolveForgeRepo(originUrl(root, run)),
|
|
165
|
+
// Built from the RESOLVED target, so `gh` is addressed at the host and
|
|
166
|
+
// directory the slug came from. The per-call ceiling is whatever is
|
|
167
|
+
// left of the whole-read budget, so a call admitted near the deadline
|
|
168
|
+
// cannot run past it.
|
|
169
|
+
apiFor: (t) => liveForgeApi(remaining, run, { host: t.host, cwd: root }),
|
|
170
|
+
remaining,
|
|
171
|
+
});
|
|
172
|
+
return forgeProtectionJson(read.reading, read.repo);
|
|
173
|
+
}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What this install does on the network — the two `doctor` surfaces that
|
|
3
|
+
* answer that question, in one module under the source-size cap.
|
|
4
|
+
*
|
|
5
|
+
* `road-to-host-traffic-knobs-that-ship` Phases 2.1 and 2.2. Its own module
|
|
6
|
+
* rather than a function inside `cmd_doctor.ts` for the reason
|
|
7
|
+
* `_lib/doctor_runtime_checks.ts` states for itself: that file is ~3,600 lines
|
|
8
|
+
* and `check_source_size_budget` counts every line above 1,500, so a change
|
|
9
|
+
* that adds lines there pays for them by taking lines away. Wiring the traffic
|
|
10
|
+
* section in costs two lines; `checkOfflineReadiness` moving here returns more
|
|
11
|
+
* than that, and lands beside a cohesive sibling rather than in an arbitrary
|
|
12
|
+
* bin — "can this install work with no registry" and "which host traffic is
|
|
13
|
+
* switched off" are the same question asked from two ends.
|
|
14
|
+
*
|
|
15
|
+
* `checkOfflineReadiness` is a PURE MOVE: same id, same statuses, same message
|
|
16
|
+
* and remedy strings. Its `pathExists` is `fs.statSync` in a try, matching the
|
|
17
|
+
* helper it used in `cmd_doctor.ts` — `existsSync` would differ on a path whose
|
|
18
|
+
* parent denies traversal, and this is a move, not a repair.
|
|
19
|
+
*
|
|
20
|
+
* Why the traffic section reports rather than decides: the variables below belong to the HOST, not to this package. Writing one into
|
|
21
|
+
* a consumer environment changes behaviour the consumer never asked to change,
|
|
22
|
+
* and — per the mapping measured in `docs/setup/host-traffic-environment.md` —
|
|
23
|
+
* could stop their background security updates as a side effect of a telemetry
|
|
24
|
+
* preference. So this module reads `env` and returns; it writes nothing, opens
|
|
25
|
+
* no socket, and touches no settings file. Two consecutive calls return equal
|
|
26
|
+
* payloads and leave the tree byte-identical.
|
|
27
|
+
*
|
|
28
|
+
* Why an inapplicable row is PRESENT and says so: the obvious implementation lists only the variables that resolve on the
|
|
29
|
+
* current host, which produces a short, clean section on a host that documents
|
|
30
|
+
* none of them. An operator reading that concludes their traffic is governed,
|
|
31
|
+
* when in fact the package simply had nothing to say. An omission that reads as
|
|
32
|
+
* a clean bill of health is the precise failure this surface exists to prevent,
|
|
33
|
+
* so a row that does not apply is emitted with the literal state
|
|
34
|
+
* {@link NOT_APPLICABLE} instead of being dropped.
|
|
35
|
+
*
|
|
36
|
+
* A variable that is SET on a host that does not document it still reports its
|
|
37
|
+
* value beside that state. The state says "this host is not known to read it";
|
|
38
|
+
* dropping the value as well would hide a fact the reader has.
|
|
39
|
+
*/
|
|
40
|
+
import * as fs from 'node:fs';
|
|
41
|
+
import * as path from 'node:path';
|
|
42
|
+
|
|
43
|
+
/** The doctor's structured check row. Mirrors `cmd_doctor`'s internal `Dict`. */
|
|
44
|
+
export interface NetworkCheck {
|
|
45
|
+
id: string;
|
|
46
|
+
status: 'ok' | 'warn' | 'fail' | 'skipped';
|
|
47
|
+
message: string;
|
|
48
|
+
remedy: string;
|
|
49
|
+
/** Structural compatibility with `cmd_doctor`'s `Dict` row type. */
|
|
50
|
+
[k: string]: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The literal a row carries where the host has no documented meaning for it. */
|
|
54
|
+
export const NOT_APPLICABLE = 'not applicable on this host';
|
|
55
|
+
|
|
56
|
+
/** The documentation surface every row points at. One copy of the mapping. */
|
|
57
|
+
export const TRAFFIC_DOC = 'docs/setup/host-traffic-environment.md';
|
|
58
|
+
|
|
59
|
+
/** Host id used when nothing in the environment identifies the host. */
|
|
60
|
+
export const UNKNOWN_HOST = 'unknown';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* One documented host traffic variable.
|
|
64
|
+
*
|
|
65
|
+
* `hosts` lists the host ids whose shipped build was actually READ for this
|
|
66
|
+
* variable — never a host somebody expects to behave the same way. A host
|
|
67
|
+
* absent from the list gets {@link NOT_APPLICABLE}, which is the honest answer
|
|
68
|
+
* and also the safe one.
|
|
69
|
+
*/
|
|
70
|
+
export interface TrafficVariable {
|
|
71
|
+
readonly variable: string;
|
|
72
|
+
readonly hosts: readonly string[];
|
|
73
|
+
/** Host build and date the row was read from, e.g. `claude-code 2.1.284 · 2026-09-29`. */
|
|
74
|
+
readonly checked_against: string;
|
|
75
|
+
/**
|
|
76
|
+
* May THIS PACKAGE write the variable into the host env block?
|
|
77
|
+
*
|
|
78
|
+
* `false` on both traffic variables and it is not a policy setting — it is a
|
|
79
|
+
* structural fact: `install.ts`'s `WRITABLE_HOST_ENV` is a two-row allow
|
|
80
|
+
* table and the settings schema admits only those two keys, so neither
|
|
81
|
+
* traffic variable is expressible anywhere in the write path. Reported
|
|
82
|
+
* because a consumer reading `set` on a row deserves to know whether this
|
|
83
|
+
* package could have been the one that set it.
|
|
84
|
+
*/
|
|
85
|
+
readonly writable_by_this_package: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The host build every row below was read from. One place to bump on a re-check. */
|
|
89
|
+
const CHECKED = 'claude-code 2.1.284 · 2026-09-29';
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The documented set, in the order `docs/setup/host-traffic-environment.md`
|
|
93
|
+
* lists it. What each one governs — and does not — lives in that page and is
|
|
94
|
+
* deliberately not duplicated here: a second copy is a second thing to keep
|
|
95
|
+
* true, and this one would be the copy nobody re-reads.
|
|
96
|
+
*/
|
|
97
|
+
export const TRAFFIC_VARIABLES: readonly TrafficVariable[] = [
|
|
98
|
+
// Both traffic variables reach the host's update-disabled resolver, the
|
|
99
|
+
// blanket one as its third rung, so neither is writable by this package —
|
|
100
|
+
// owner-decided 2026-09-30.
|
|
101
|
+
{ variable: 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: false },
|
|
102
|
+
{ variable: 'DISABLE_AUTOUPDATER', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: false },
|
|
103
|
+
// Size caps. Neither reaches the updater resolver, and neither suppresses a
|
|
104
|
+
// call, an update check or a download.
|
|
105
|
+
{ variable: 'BASH_MAX_OUTPUT_LENGTH', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: true },
|
|
106
|
+
{ variable: 'MAX_MCP_OUTPUT_TOKENS', hosts: ['claude-code'], checked_against: CHECKED, writable_by_this_package: true },
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
/** An environment map, in the shape `process.env` has. */
|
|
110
|
+
export type EnvMap = Readonly<Record<string, string | undefined>>;
|
|
111
|
+
|
|
112
|
+
/** Which host this process is running under, and whether that was observed. */
|
|
113
|
+
export interface TrafficHost {
|
|
114
|
+
host: string;
|
|
115
|
+
observed: boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the host from the environment it exported.
|
|
120
|
+
*
|
|
121
|
+
* `observed` carries the same distinction `routing:doctor` draws for its own
|
|
122
|
+
* platform field: a host that identified itself is a fact, and the absence of
|
|
123
|
+
* any marker is NOT evidence of a different host — only evidence that nobody
|
|
124
|
+
* said. An unidentified host resolves to {@link UNKNOWN_HOST}, which documents
|
|
125
|
+
* no variable, so every row reads {@link NOT_APPLICABLE} rather than reporting
|
|
126
|
+
* against a host this code guessed at.
|
|
127
|
+
*/
|
|
128
|
+
export function resolveTrafficHost(env: EnvMap): TrafficHost {
|
|
129
|
+
const claude =
|
|
130
|
+
(env['CLAUDECODE'] ?? '').trim() !== '' || (env['CLAUDE_CODE_SESSION_ID'] ?? '').trim() !== '';
|
|
131
|
+
if (claude) return { host: 'claude-code', observed: true };
|
|
132
|
+
return { host: UNKNOWN_HOST, observed: false };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** One emitted row: the variable, its state on this host, and its value if set. */
|
|
136
|
+
export interface TrafficRow {
|
|
137
|
+
variable: string;
|
|
138
|
+
state: string;
|
|
139
|
+
value: string | null;
|
|
140
|
+
checked_against: string;
|
|
141
|
+
writable_by_this_package: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Build one row. A variable the host does not document reports
|
|
146
|
+
* {@link NOT_APPLICABLE} whether or not it happens to be exported.
|
|
147
|
+
*/
|
|
148
|
+
function trafficRow(spec: TrafficVariable, env: EnvMap, host: string): TrafficRow {
|
|
149
|
+
const raw = env[spec.variable];
|
|
150
|
+
const present = raw !== undefined && raw !== '';
|
|
151
|
+
const applicable = spec.hosts.includes(host);
|
|
152
|
+
return {
|
|
153
|
+
variable: spec.variable,
|
|
154
|
+
state: applicable ? (present ? 'set' : 'unset') : NOT_APPLICABLE,
|
|
155
|
+
value: present ? String(raw) : null,
|
|
156
|
+
checked_against: spec.checked_against,
|
|
157
|
+
writable_by_this_package: spec.writable_by_this_package,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The `traffic_environment` block of `agent-config doctor --json`.
|
|
163
|
+
*
|
|
164
|
+
* Read-only by construction: the only input is the injected `env` map, and the
|
|
165
|
+
* only output is a fresh object. `hostOverride` is the test seam Phase 2.2's
|
|
166
|
+
* non-Claude fixture needs, and is never passed by the production call site.
|
|
167
|
+
*
|
|
168
|
+
* `reporting_read_only` replaced a flat `read_only: true` on 2026-09-30, and the
|
|
169
|
+
* rename is the point rather than cosmetics: this REPORT is still read-only, but
|
|
170
|
+
* the PACKAGE is no longer, so the old key had become a true statement about the
|
|
171
|
+
* wrong subject. Two of the four rows are now writable by the installer when the
|
|
172
|
+
* consumer sets a cap, and `writable_by_this_package` says which — a consumer
|
|
173
|
+
* reading `set` deserves to know whether we could have been the one who set it.
|
|
174
|
+
*/
|
|
175
|
+
export function trafficEnvironmentJson(
|
|
176
|
+
env: EnvMap,
|
|
177
|
+
hostOverride?: TrafficHost,
|
|
178
|
+
): Record<string, unknown> {
|
|
179
|
+
const resolved = hostOverride ?? resolveTrafficHost(env);
|
|
180
|
+
return {
|
|
181
|
+
host: resolved.host,
|
|
182
|
+
host_observed: resolved.observed,
|
|
183
|
+
doc: TRAFFIC_DOC,
|
|
184
|
+
reporting_read_only: true,
|
|
185
|
+
writable_by_this_package: TRAFFIC_VARIABLES.filter((v) => v.writable_by_this_package).map(
|
|
186
|
+
(v) => v.variable,
|
|
187
|
+
),
|
|
188
|
+
rows: TRAFFIC_VARIABLES.map((spec) => trafficRow(spec, env, resolved.host)),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** `fs.statSync` in a try — the `cmd_doctor.ts` helper this move preserves. */
|
|
193
|
+
function pathExists(p: string): boolean {
|
|
194
|
+
try {
|
|
195
|
+
fs.statSync(p);
|
|
196
|
+
return true;
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The `offline-readiness` check — a pure move out of `cmd_doctor.ts`.
|
|
204
|
+
*
|
|
205
|
+
* `packageRoot` is passed IN rather than resolved here for the reason
|
|
206
|
+
* `doctor_runtime_checks.ts` gives for its `which` parameter: `_package_root`
|
|
207
|
+
* lives in `cmd_doctor.ts` and importing it back would make the two modules
|
|
208
|
+
* circular.
|
|
209
|
+
*/
|
|
210
|
+
export function checkOfflineReadiness(packageRoot: string): NetworkCheck {
|
|
211
|
+
const script = path.join(packageRoot, 'src', 'scripts', 'hermetic-install.sh');
|
|
212
|
+
if (!pathExists(script)) {
|
|
213
|
+
return {
|
|
214
|
+
id: 'offline-readiness',
|
|
215
|
+
status: 'warn',
|
|
216
|
+
message: 'src/scripts/hermetic-install.sh not found in package',
|
|
217
|
+
remedy: 'reinstall @event4u/agent-config or pull missing files',
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
id: 'offline-readiness',
|
|
222
|
+
status: 'ok',
|
|
223
|
+
message: 'verified-offline install entrypoint present',
|
|
224
|
+
remedy: '',
|
|
225
|
+
};
|
|
226
|
+
}
|