@event4u/agent-config 9.7.0 → 9.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +314 -190
- package/CONTRIBUTING.md +23 -7
- package/MIGRATION.md +20 -0
- package/README.md +57 -11
- package/dist/agent-src/commands/agents/audit.md +1 -1
- package/dist/agent-src/commands/agents/optimize.md +2 -2
- package/dist/agent-src/commands/agents/user.md +1 -1
- package/dist/agent-src/commands/agents.md +1 -1
- package/dist/agent-src/commands/check-current-md.md +3 -3
- package/dist/agent-src/commands/commit/in-chunks.md +8 -0
- package/dist/agent-src/commands/commit.md +17 -0
- package/dist/agent-src/commands/fix/portability.md +2 -2
- package/dist/agent-src/commands/fix/pr-comments-loop.md +136 -0
- package/dist/agent-src/commands/fix/refs.md +2 -2
- package/dist/agent-src/commands/fix/route.md +4 -3
- package/dist/agent-src/commands/fix.md +9 -6
- package/dist/agent-src/commands/ghostwriter.md +1 -1
- package/dist/agent-src/commands/image.md +1 -1
- package/dist/agent-src/commands/optimize/augmentignore.md +1 -1
- package/dist/agent-src/commands/optimize/skills.md +2 -2
- package/dist/agent-src/commands/post-as.md +1 -1
- package/dist/agent-src/commands/pr/create.md +4 -0
- package/dist/agent-src/commands/research.md +1 -1
- package/dist/agent-src/commands/roadmap/ai-council.md +1 -1
- package/dist/agent-src/commands/security-audit-config.md +1 -1
- package/dist/agent-src/commands/team/delegate.md +4 -0
- package/dist/agent-src/commands/video.md +1 -1
- package/dist/agent-src/contexts/authority/kernel-rule-edits.md +1 -1
- package/dist/agent-src/contexts/contracts/emergency-triage-block.md +2 -2
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +48 -2
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +10 -0
- package/dist/agent-src/contexts/execution/subagent-modes-detail.md +109 -8
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +20 -0
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +53 -3
- package/dist/agent-src/contexts/override-system.md +75 -5
- package/dist/agent-src/rules/code-provenance.md +112 -0
- package/dist/agent-src/rules/context-hygiene.md +2 -0
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +97 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +13 -3
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +2 -0
- package/dist/agent-src/rules/git-history-discipline.md +2 -0
- package/dist/agent-src/rules/history-discipline.md +80 -0
- package/dist/agent-src/rules/language-and-tone.md +2 -0
- package/dist/agent-src/rules/lethal-trifecta-guard.md +3 -0
- package/dist/agent-src/rules/media-governance-routing.md +2 -0
- package/dist/agent-src/rules/minimal-safe-diff.md +2 -0
- package/dist/agent-src/rules/no-roadmap-references.md +4 -1
- package/dist/agent-src/rules/non-destructive-by-default.md +20 -0
- package/dist/agent-src/rules/onboarding-gate.md +2 -0
- package/dist/agent-src/rules/output-discipline.md +2 -0
- package/dist/agent-src/rules/persona-governance.md +2 -0
- package/dist/agent-src/rules/php-coding.md +1 -0
- package/dist/agent-src/rules/preservation-guard.md +3 -0
- package/dist/agent-src/rules/reviewer-awareness.md +1 -0
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +9 -0
- package/dist/agent-src/rules/scale-discipline.md +92 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +106 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +11 -1
- package/dist/agent-src/rules/session-canary.md +77 -0
- package/dist/agent-src/rules/skill-quality.md +2 -0
- package/dist/agent-src/rules/source-confidentiality.md +2 -0
- package/dist/agent-src/rules/source-of-truth.md +2 -0
- package/dist/agent-src/rules/telegraph-speak.md +2 -0
- package/dist/agent-src/rules/token-optimizer-maintenance.md +3 -1
- package/dist/agent-src/rules/tool-safety.md +4 -1
- package/dist/agent-src/rules/untrusted-input-defense.md +10 -0
- package/dist/agent-src/rules/verify-before-complete.md +2 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +17 -1
- package/dist/agent-src/skills/agent-security-review/SKILL.md +1 -1
- package/dist/agent-src/skills/code-intelligence/SKILL.md +97 -0
- package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +0 -3
- package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
- package/dist/agent-src/skills/design-review/SKILL.md +5 -6
- package/dist/agent-src/skills/design-tokens/SKILL.md +0 -1
- package/dist/agent-src/skills/gated-reach/SKILL.md +185 -0
- package/dist/agent-src/skills/gated-reach/evals/triggers.json +72 -0
- package/dist/agent-src/skills/history-design/SKILL.md +101 -0
- package/dist/agent-src/skills/history-design/evals/triggers.json +17 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +3 -3
- package/dist/agent-src/skills/image-analyser/SKILL.md +14 -12
- package/dist/agent-src/skills/image-editing/SKILL.md +2 -1
- package/dist/agent-src/skills/image-generation/SKILL.md +2 -1
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/launch-readiness/SKILL.md +1 -1
- package/dist/agent-src/skills/license-compliance-audit/SKILL.md +161 -0
- package/dist/agent-src/skills/license-compliance-audit/evals/triggers.json +52 -0
- package/dist/agent-src/skills/license-compliance-borrow-check/SKILL.md +145 -0
- package/dist/agent-src/skills/license-compliance-borrow-check/evals/triggers.json +52 -0
- package/dist/agent-src/skills/license-compliance-credits/SKILL.md +97 -0
- package/dist/agent-src/skills/license-compliance-credits/evals/triggers.json +52 -0
- package/dist/agent-src/skills/md-language-check/SKILL.md +1 -1
- package/dist/agent-src/skills/override-management/SKILL.md +1 -1
- package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +7 -7
- package/dist/agent-src/skills/project-analysis-core/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -2
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +2 -2
- package/dist/agent-src/skills/readme-writing/SKILL.md +6 -1
- package/dist/agent-src/skills/recursive-verification/SKILL.md +6 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -3
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +4 -0
- package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +31 -12
- package/dist/agent-src/skills/rule-refactor/SKILL.md +3 -3
- package/dist/agent-src/skills/schema-review/SKILL.md +92 -0
- package/dist/agent-src/skills/schema-review/evals/triggers.json +17 -0
- package/dist/agent-src/skills/screenshot-hygiene/SKILL.md +171 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +43 -1
- package/dist/agent-src/skills/security-audit/SKILL.md +1 -1
- package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -3
- package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/source-discovery/SKILL.md +5 -5
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +45 -85
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +5 -4
- package/dist/agent-src/skills/subagent-orchestration/prompts/adversarial-verification-council.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-and-judge-two-stage.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-and-judge.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-competitively.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-parallel.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-steps.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/do-in-worktrees.md +29 -0
- package/dist/agent-src/skills/subagent-orchestration/prompts/judge-with-debate.md +29 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +2 -3
- package/dist/agent-src/skills/token-optimizer/SKILL.md +4 -4
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +4 -0
- package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +2 -3
- package/dist/agent-src/templates/AGENTS.md +1 -1
- package/dist/agent-src/templates/agents/.gitattributes.fragment +25 -6
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/command.md +3 -3
- package/dist/agent-src/templates/github-workflows/secret-scan.yml +65 -0
- package/dist/agent-src/templates/persona.md +2 -2
- package/dist/agent-src/templates/rule.md +2 -2
- package/dist/agent-src/templates/scripts/telemetry/engagement.ts +77 -0
- package/dist/agent-src/templates/scripts/telemetry_record.ts +33 -1
- package/dist/cli/commands/doctorShell.js +20 -0
- package/dist/cli/commands/doctorShell.js.map +1 -1
- package/dist/cli/commands/rtkDetect.js +58 -0
- package/dist/cli/commands/rtkDetect.js.map +1 -0
- package/dist/cli/configRoot.js +112 -0
- package/dist/cli/configRoot.js.map +1 -0
- package/dist/cli/configRoot.test.js +97 -0
- package/dist/cli/configRoot.test.js.map +1 -0
- package/dist/cli/firstRunNotice.js +70 -0
- package/dist/cli/firstRunNotice.js.map +1 -0
- package/dist/cli/help.js +4 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +54 -5
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/registry.js +8 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +502 -101
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +6 -4
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +95 -8
- package/dist/discovery/trust-report.md +11 -11
- package/dist/discovery/workspaces.json +36 -7
- package/dist/hooks/dispatch.js +19475 -0
- package/dist/install/agentSwitchDetection.js +75 -0
- package/dist/install/agentSwitchDetection.js.map +1 -0
- package/dist/install/agentSwitchProfile.js +117 -0
- package/dist/install/agentSwitchProfile.js.map +1 -0
- package/dist/install/atomic.js +1 -1
- package/dist/install/detect.js +1 -1
- package/dist/install/install.mjs +791 -486
- package/dist/install/rtkDetection.js +213 -0
- package/dist/install/rtkDetection.js.map +1 -0
- package/dist/install/rule_scope.js +2 -1
- package/dist/install/rule_scope.js.map +1 -1
- package/dist/install/types.js +2 -2
- package/dist/install/wizard-plan.js +1 -1
- package/dist/install/wizardDismissals.js +58 -0
- package/dist/install/wizardDismissals.js.map +1 -0
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
- package/dist/mcp/registry-manifest.json +15 -4
- package/dist/mcp/server.json +20 -0
- package/dist/mcp/server.mjs +44292 -0
- package/dist/router.json +1 -1
- package/dist/scripts/condense.js +14 -7
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/app.js +12 -0
- package/dist/server/app.js.map +1 -1
- package/dist/server/io/sharedWriteCheck.js +101 -0
- package/dist/server/io/sharedWriteCheck.js.map +1 -0
- package/dist/server/routes/ping.js +32 -0
- package/dist/server/routes/ping.js.map +1 -1
- package/dist/server/routes/settings.js +21 -4
- package/dist/server/routes/settings.js.map +1 -1
- package/dist/server/routes/userMd.js +21 -4
- package/dist/server/routes/userMd.js.map +1 -1
- package/dist/server/routes/wizard.js +68 -25
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/server/schemas/settings.js +12 -2
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/server/serverInfo.js +6 -2
- package/dist/server/serverInfo.js.map +1 -1
- package/dist/server/token.js +11 -4
- package/dist/server/token.js.map +1 -1
- package/dist/server/writeRoot.js +15 -1
- package/dist/server/writeRoot.js.map +1 -1
- package/dist/shared/capabilities.js +33 -0
- package/dist/shared/capabilities.js.map +1 -0
- package/dist/shared/capabilities.test.js +39 -0
- package/dist/shared/capabilities.test.js.map +1 -0
- package/dist/ui/assets/index-BpSQt5vm.js +40 -0
- package/dist/ui/assets/index-BpSQt5vm.js.map +1 -0
- package/dist/ui/assets/index-jSfMW8_t.css +1 -0
- package/dist/ui/index.html +15 -6
- package/docs/MIGRATION.md +16 -0
- package/docs/guidelines/component-oriented-and-oop-development.md +4 -2
- package/package.json +22 -9
- package/src/agent-src/templates/AGENTS.md +1 -1
- package/src/agent-src/templates/scripts/telemetry/engagement.ts +77 -0
- package/src/agent-src/templates/scripts/telemetry_record.ts +33 -1
- package/src/config/agent-settings.template.yml +94 -13
- package/src/config/discovery/packs.yml +22 -0
- package/src/config/discovery/workspaces.yml +1 -1
- package/src/config/evaluator-budgets.json +47 -0
- package/src/config/hook-latency-budget.json +20 -0
- package/src/config/reach-channels.yml +217 -0
- package/src/config/reach-prescriptions-intake.yml +200 -0
- package/src/install/agentSwitchDetection.ts +90 -0
- package/src/install/agentSwitchProfile.ts +131 -0
- package/src/install/atomic.ts +1 -1
- package/src/install/detect.ts +1 -1
- package/src/install/rtkDetection.ts +274 -0
- package/src/install/rule_scope.ts +9 -2
- package/src/install/types.ts +2 -2
- package/src/install/wizard-plan.ts +1 -1
- package/src/install/wizardDismissals.ts +60 -0
- package/src/scripts/_cli/cmd_doctor.ts +62 -1
- package/src/scripts/_cli/cmd_memory_get.ts +197 -0
- package/src/scripts/_cli/cmd_refresh.ts +30 -0
- package/src/scripts/_dispatch.bash +96 -0
- package/src/scripts/_lib/auto_dispatch.corpus.test.ts +64 -1
- package/src/scripts/_lib/auto_dispatch.ts +76 -0
- package/src/scripts/_lib/detect_target_license.ts +714 -0
- package/src/scripts/_lib/exec_evidence.ts +251 -0
- package/src/scripts/_lib/fixtures/secret-detector/negatives.txt +15 -0
- package/src/scripts/_lib/fixtures/secret-detector/positives.txt +15 -0
- package/src/scripts/_lib/install_drift.ts +194 -0
- package/src/scripts/_lib/kernel_rules.ts +46 -0
- package/src/scripts/_lib/memory_fts_index.ts +390 -0
- package/src/scripts/_lib/orchestration_record.ts +91 -2
- package/src/scripts/_lib/persistence/adapter_raw_sql.ts +443 -0
- package/src/scripts/_lib/persistence/detect_audit_coverage.ts +423 -0
- package/src/scripts/_lib/persistence/detect_bounded_reads.ts +154 -0
- package/src/scripts/_lib/persistence/detect_index_parity.ts +576 -0
- package/src/scripts/_lib/persistence/detect_n1_eloquent.ts +226 -0
- package/src/scripts/_lib/persistence/detect_offload.ts +441 -0
- package/src/scripts/_lib/persistence/detect_prisma_growth.ts +74 -0
- package/src/scripts/_lib/persistence/offload_catalog.ts +73 -0
- package/src/scripts/_lib/persistence/types.ts +109 -0
- package/src/scripts/_lib/reddit_thread_parse.ts +598 -0
- package/src/scripts/_lib/risk_paths.ts +160 -0
- package/src/scripts/_lib/rtk_allowlist.ts +44 -0
- package/src/scripts/_lib/secret_detector.test.ts +108 -0
- package/src/scripts/_lib/secret_detector.ts +328 -0
- package/src/scripts/_lib/secret_detector_adversarial.test.ts +116 -0
- package/src/scripts/_lib/spawn_env.ts +7 -0
- package/src/scripts/_lib/sqlite_guard.ts +191 -0
- package/src/scripts/_lib/subagent_spawn.ts +53 -0
- package/src/scripts/_lib/tool_probe.ts +359 -0
- package/src/scripts/_lib/worker_budget.ts +107 -0
- package/src/scripts/adr/regenerate_index.ts +81 -6
- package/src/scripts/ai_council/blind_review.ts +0 -0
- package/src/scripts/ai_council/config.ts +12 -6
- package/src/scripts/ai_council/orchestrator.ts +73 -3
- package/src/scripts/ai_team/review_gate.ts +8 -10
- package/src/scripts/ai_team/team_dispatch.ts +48 -0
- package/src/scripts/audit_adr_coverage.ts +33 -0
- package/src/scripts/audit_initial_context.ts +1 -1
- package/src/scripts/bench_cross_source_eval.ts +400 -0
- package/src/scripts/bench_honesty_score.ts +1093 -0
- package/src/scripts/bench_hook_latency.ts +218 -0
- package/src/scripts/build_mcp_catalog.ts +275 -0
- package/src/scripts/build_mcp_registry_manifest.ts +46 -0
- package/src/scripts/build_proof.ts +207 -0
- package/src/scripts/chat_history.ts +8 -5
- package/src/scripts/check_adr_frontmatter.ts +195 -0
- package/src/scripts/check_artefact_count_messaging.ts +4 -0
- package/src/scripts/check_backstop_debt.ts +210 -0
- package/src/scripts/check_bundle_path_leakage.ts +343 -0
- package/src/scripts/check_claims.ts +188 -8
- package/src/scripts/check_comparison.ts +12 -0
- package/src/scripts/check_enforcement_coverage.ts +592 -0
- package/src/scripts/check_evaluator_budgets.ts +99 -0
- package/src/scripts/check_kernel_rule_bundle.ts +16 -12
- package/src/scripts/check_knowledge_sharing.ts +12 -1
- package/src/scripts/check_no_external_sources.ts +2 -2
- package/src/scripts/check_reach_channels.ts +407 -0
- package/src/scripts/check_reach_staleness.ts +364 -0
- package/src/scripts/check_secret_leak.test.ts +47 -0
- package/src/scripts/check_secret_leak.ts +290 -0
- package/src/scripts/check_source_pointer_freshness.ts +28 -3
- package/src/scripts/code_graph/build.ts +0 -0
- package/src/scripts/code_graph/cli.ts +379 -0
- package/src/scripts/code_graph/detect.ts +186 -0
- package/src/scripts/code_graph/extract.ts +386 -0
- package/src/scripts/code_graph/intent.ts +45 -0
- package/src/scripts/code_graph/loader.ts +123 -0
- package/src/scripts/code_graph/query.ts +290 -0
- package/src/scripts/code_graph/sanitize.ts +30 -0
- package/src/scripts/code_graph/sqlite_store.ts +174 -0
- package/src/scripts/code_graph/types.ts +83 -0
- package/src/scripts/code_graph/validate.ts +63 -0
- package/src/scripts/condense.ts +14 -6
- package/src/scripts/context_hygiene_hook.ts +8 -5
- package/src/scripts/council_cli.ts +126 -12
- package/src/scripts/detect_target_license.ts +203 -0
- package/src/scripts/evaluator_umbrella.sh +145 -0
- package/src/scripts/external_sources_denylist.json +8 -4
- package/src/scripts/first_run_gate_hook.ts +9 -5
- package/src/scripts/generate_subagent_floor.ts +194 -0
- package/src/scripts/hermetic-install.sh +3 -3
- package/src/scripts/hook_manifest.yaml +65 -16
- package/src/scripts/hooks/block_kernel_rule_writes.ts +212 -0
- package/src/scripts/hooks/block_no_verify.ts +9 -9
- package/src/scripts/hooks/code_graph_nudge_hook.ts +191 -0
- package/src/scripts/hooks/concern_registry.ts +75 -0
- package/src/scripts/hooks/design_slop_hook.ts +8 -5
- package/src/scripts/hooks/dispatch_entry.ts +37 -0
- package/src/scripts/hooks/dispatch_hook.ts +176 -3
- package/src/scripts/hooks/hook_stdin.ts +42 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +26 -12
- package/src/scripts/hot_context_hook.ts +7 -6
- package/src/scripts/injection_scan_hook.ts +9 -1
- package/src/scripts/install +6 -6
- package/src/scripts/install-hooks.sh +4 -4
- package/src/scripts/install.sh +5 -4
- package/src/scripts/install.ts +264 -23
- package/src/scripts/iron_law_sha.ts +3 -12
- package/src/scripts/learning_sidecar.ts +0 -0
- package/src/scripts/lint_budget_ownership.ts +89 -0
- package/src/scripts/lint_command_routing.ts +35 -5
- package/src/scripts/lint_command_verbs.ts +42 -9
- package/src/scripts/lint_consumer_internal_refs.ts +211 -0
- package/src/scripts/lint_discovery_vocabulary.ts +2 -0
- package/src/scripts/lint_documented_commands.ts +670 -0
- package/src/scripts/lint_framework_leakage.ts +17 -3
- package/src/scripts/lint_framework_leakage_allowlist.json +32 -0
- package/src/scripts/lint_governed_writes.ts +335 -0
- package/src/scripts/lint_hidden_unicode.ts +6 -0
- package/src/scripts/lint_mcp_registry_manifest.ts +26 -1
- package/src/scripts/lint_memory_tripwire.ts +186 -0
- package/src/scripts/lint_override_kernel_guard.ts +267 -0
- package/src/scripts/lint_persistence.ts +171 -0
- package/src/scripts/lint_pre_migration_refs.ts +106 -0
- package/src/scripts/lint_provenance.ts +547 -0
- package/src/scripts/lint_provenance_vocabulary.ts +437 -0
- package/src/scripts/lint_spawn_payload.ts +283 -0
- package/src/scripts/lint_store_boundary.ts +152 -0
- package/src/scripts/lint_versioned_cache.ts +7 -1
- package/src/scripts/mcp_server/__main__.ts +7 -2
- package/src/scripts/mcp_server/catalog.ts +23 -1
- package/src/scripts/mcp_server/consumer_tool_catalog.json +563 -193
- package/src/scripts/mcp_server/prompts.ts +6 -0
- package/src/scripts/mcp_server/tool_catalog_source.ts +332 -0
- package/src/scripts/mcp_server/tools.ts +56 -5
- package/src/scripts/mcp_telemetry_query.ts +2 -33
- package/src/scripts/mcp_telemetry_store.ts +64 -34
- package/src/scripts/measure_rule_budget.ts +3 -12
- package/src/scripts/memory_learn_hook.ts +126 -0
- package/src/scripts/memory_lookup.ts +0 -0
- package/src/scripts/memory_replay_24.ts +312 -0
- package/src/scripts/memory_report.ts +16 -3
- package/src/scripts/memory_signal.ts +48 -0
- package/src/scripts/memory_status.ts +6 -0
- package/src/scripts/minimal_safe_diff_hook.ts +8 -5
- package/src/scripts/onboarding_gate_hook.ts +8 -5
- package/src/scripts/orchestration_record.ts +16 -0
- package/src/scripts/pr_url_reminder_hook.ts +8 -1
- package/src/scripts/prepack-check.mjs +17 -0
- package/src/scripts/prepack_lifecycle_check.d.mts +8 -0
- package/src/scripts/prepack_lifecycle_check.mjs +82 -0
- package/src/scripts/profile_staleness_hook.ts +8 -7
- package/src/scripts/reach_doctor.ts +1651 -0
- package/src/scripts/release.ts +24 -3
- package/src/scripts/report_install_drift.ts +109 -0
- package/src/scripts/risk_escalation_shadow.ts +160 -0
- package/src/scripts/roadmap_progress_hook.ts +8 -5
- package/src/scripts/schemas/agent-settings.schema.json +23 -0
- package/src/scripts/schemas/license-policy.schema.json +89 -0
- package/src/scripts/schemas/provenance-borrow.schema.json +46 -0
- package/src/scripts/schemas/reach-channels.schema.json +134 -0
- package/src/scripts/schemas/reach-doctor-payload.schema.json +220 -0
- package/src/scripts/schemas/rule.schema.json +20 -0
- package/src/scripts/self_review_gate.test.ts +173 -1
- package/src/scripts/self_review_gate.ts +155 -15
- package/src/scripts/session_canary_hook.ts +182 -0
- package/src/scripts/skill_linter.ts +55 -0
- package/src/scripts/smoke_quickstart.ts +2 -2
- package/src/scripts/surface_probe_hook.ts +8 -7
- package/src/scripts/sync_gitattributes.ts +310 -0
- package/src/scripts/team_review_gate_hook.ts +13 -16
- package/src/scripts/validate_reach_prescriptions.ts +751 -0
- package/src/scripts/verify_before_complete_hook.ts +8 -5
- package/src/scripts/wrapper_freshness_hook.ts +8 -7
- package/src/server/schemas/settings.ts +24 -2
- package/src/shared/capabilities.test.ts +43 -0
- package/src/shared/capabilities.ts +75 -0
- package/src/templates/minimal/agents-overrides-readme.md +20 -0
- package/dist/ui/assets/index-BPFMZWUs.css +0 -1
- package/dist/ui/assets/index-BiEZiZ31.js +0 -40
- package/dist/ui/assets/index-BiEZiZ31.js.map +0 -1
- package/docs/CLAIMS.md +0 -261
- package/docs/DISTRIBUTION_CHECKLIST.md +0 -170
- package/docs/RELEASE_STORY_TEMPLATE.md +0 -37
- package/docs/SKILL_CENSUS.md +0 -352
- package/docs/adrs/cost/0001-hard-stop-hook.md +0 -114
- package/docs/adrs/cost/README.md +0 -9
- package/docs/adrs/memory/0001-consumer-side-snapshot.md +0 -119
- package/docs/adrs/memory/README.md +0 -10
- package/docs/adrs/router/0001-three-tier-routing.md +0 -119
- package/docs/adrs/router/README.md +0 -9
- package/docs/adrs/schema/0001-json-schema-frontmatter.md +0 -102
- package/docs/adrs/schema/README.md +0 -9
- package/docs/adrs/smoke/0001-per-tier-smoke-scripts.md +0 -99
- package/docs/adrs/smoke/README.md +0 -9
- package/docs/adrs/telegraph/0001-default-off-until-bench.md +0 -93
- package/docs/adrs/telegraph/README.md +0 -9
- package/docs/announcements/2026-05-non-dev-launch.md +0 -79
- package/docs/announcements/2026-07-honest-cost-sweep-launch.md +0 -84
- package/docs/anti-reskin-gate.md +0 -60
- package/docs/architecture/augment-projection.md +0 -70
- package/docs/architecture/claude-bundle.md +0 -77
- package/docs/architecture/current-onboard-baseline.md +0 -126
- package/docs/architecture/current-safety-behavior.md +0 -137
- package/docs/architecture/multi-tool-projection.md +0 -125
- package/docs/architecture/setup-vs-settings-shared-surface.md +0 -114
- package/docs/architecture/source-projection.md +0 -85
- package/docs/architecture.md +0 -390
- package/docs/archive/CHANGELOG-6.0.0-overview.md +0 -953
- package/docs/archive/CHANGELOG-7.0.0.md +0 -419
- package/docs/archive/CHANGELOG-pre-2.11.0.md +0 -141
- package/docs/archive/CHANGELOG-pre-2.15.0.md +0 -244
- package/docs/archive/CHANGELOG-pre-2.16.0.md +0 -48
- package/docs/archive/CHANGELOG-pre-2.17.0.md +0 -63
- package/docs/archive/CHANGELOG-pre-2.2.0.md +0 -2138
- package/docs/archive/CHANGELOG-pre-2.20.0.md +0 -159
- package/docs/archive/CHANGELOG-pre-2.25.0.md +0 -191
- package/docs/archive/CHANGELOG-pre-2.7.0.md +0 -185
- package/docs/archive/CHANGELOG-pre-3.0.0.md +0 -130
- package/docs/archive/CHANGELOG-pre-3.1.0.md +0 -167
- package/docs/archive/CHANGELOG-pre-3.2.0.md +0 -268
- package/docs/archive/CHANGELOG-pre-4.0.0.md +0 -80
- package/docs/archive/CHANGELOG-pre-4.5.0.md +0 -289
- package/docs/archive/CHANGELOG-pre-5.4.0.md +0 -260
- package/docs/archive/CHANGELOG-pre-5.9.0.md +0 -270
- package/docs/archive/CHANGELOG-pre-6.0.0.md +0 -473
- package/docs/archive/CHANGELOG-pre-7.0.0.md +0 -126
- package/docs/archive/CHANGELOG-pre-8.0.0.md +0 -301
- package/docs/archive/CHANGELOG-pre-8.1.0.md +0 -316
- package/docs/archive/CHANGELOG-pre-8.12.0.md +0 -304
- package/docs/archive/CHANGELOG-pre-8.9.0.md +0 -306
- package/docs/archive/CHANGELOG-pre-9.2.0.md +0 -276
- package/docs/artefact-census.md +0 -71
- package/docs/benchmark.md +0 -648
- package/docs/benchmark.pinned.yml +0 -31
- package/docs/benchmarks.md +0 -85
- package/docs/capability-matrix.md +0 -33
- package/docs/case-studies/_template.md +0 -60
- package/docs/case-studies/frontend-design-positioning.md +0 -86
- package/docs/catalog.md +0 -721
- package/docs/command-flows.md +0 -272
- package/docs/command-naming-audit.md +0 -60
- package/docs/comparison.yaml +0 -45
- package/docs/contracts/CHANGELOG-conventions.md +0 -149
- package/docs/contracts/STABILITY.md +0 -188
- package/docs/contracts/adoption-signal-floor.md +0 -127
- package/docs/contracts/adr-architectural-consensus-mechanism.md +0 -68
- package/docs/contracts/adr-chat-history-split.md +0 -140
- package/docs/contracts/adr-command-suggestion.md +0 -144
- package/docs/contracts/adr-forecast-construction-shape.md +0 -90
- package/docs/contracts/adr-gtm-context-spine.md +0 -116
- package/docs/contracts/adr-implement-ticket-runtime.md +0 -121
- package/docs/contracts/adr-install-user-type-axis.md +0 -107
- package/docs/contracts/adr-layout.md +0 -107
- package/docs/contracts/adr-level-6-productization.md +0 -145
- package/docs/contracts/adr-mcp-runtime.md +0 -128
- package/docs/contracts/adr-product-ui-track.md +0 -381
- package/docs/contracts/adr-prompt-driven-execution.md +0 -186
- package/docs/contracts/adr-settings-sync-engine.md +0 -128
- package/docs/contracts/adr-user-types-axis.md +0 -127
- package/docs/contracts/adr-wing4-context-spine.md +0 -126
- package/docs/contracts/agent-user-schema.md +0 -170
- package/docs/contracts/agents-layout.md +0 -148
- package/docs/contracts/agents-md-tech-stack.md +0 -75
- package/docs/contracts/ai-council-config.md +0 -829
- package/docs/contracts/ai-team-config.md +0 -224
- package/docs/contracts/analysis-memory-loop.md +0 -149
- package/docs/contracts/at-rest-encryption.md +0 -191
- package/docs/contracts/audit-log-v1.md +0 -150
- package/docs/contracts/auto-orchestration-v1.md +0 -70
- package/docs/contracts/benchmark-ab-contract.md +0 -106
- package/docs/contracts/benchmark-corpus-spec.md +0 -125
- package/docs/contracts/benchmark-report-schema.md +0 -113
- package/docs/contracts/branch-protection-policy.md +0 -139
- package/docs/contracts/brand-token-consumption.md +0 -74
- package/docs/contracts/capability-boundary.md +0 -69
- package/docs/contracts/capability-packs.md +0 -217
- package/docs/contracts/ci-cost-budget.md +0 -111
- package/docs/contracts/ci-green-floor.md +0 -141
- package/docs/contracts/command-category-governance.md +0 -84
- package/docs/contracts/command-clusters.md +0 -399
- package/docs/contracts/command-surface-tiers.md +0 -176
- package/docs/contracts/command-taxonomy.md +0 -137
- package/docs/contracts/condensation-default-kill-criterion.md +0 -116
- package/docs/contracts/config-presets.md +0 -144
- package/docs/contracts/conformance.md +0 -84
- package/docs/contracts/consumer-bridge.md +0 -73
- package/docs/contracts/context-paths.md +0 -101
- package/docs/contracts/context-spine.md +0 -179
- package/docs/contracts/cost-dashboard.md +0 -143
- package/docs/contracts/cost-enforcement.md +0 -134
- package/docs/contracts/cost-profile-defaults.md +0 -110
- package/docs/contracts/cost-summary-schema.md +0 -107
- package/docs/contracts/creative-pack-boundary.md +0 -63
- package/docs/contracts/cross-repo-retrieval.md +0 -64
- package/docs/contracts/cross-wing-handoff.md +0 -134
- package/docs/contracts/daily-workspace.md +0 -147
- package/docs/contracts/decision-engine-gates.md +0 -120
- package/docs/contracts/decision-trace-v1.md +0 -177
- package/docs/contracts/design-artifact-lifecycle.md +0 -93
- package/docs/contracts/design-artifact-verification.md +0 -153
- package/docs/contracts/discovery-manifest.md +0 -209
- package/docs/contracts/discovery-manifest.schema.json +0 -254
- package/docs/contracts/evidence-based-pruning.md +0 -102
- package/docs/contracts/explain-modes.md +0 -187
- package/docs/contracts/explain-trace.schema.json +0 -144
- package/docs/contracts/file-ownership-matrix.json +0 -13941
- package/docs/contracts/file-ownership-matrix.md +0 -135
- package/docs/contracts/frontmatter-contract.md +0 -140
- package/docs/contracts/ghostwriter-schema.md +0 -337
- package/docs/contracts/governance-enforcement-projection.md +0 -159
- package/docs/contracts/gui-wizard.md +0 -350
- package/docs/contracts/harness-expectations.md +0 -128
- package/docs/contracts/hook-architecture-v1.md +0 -325
- package/docs/contracts/host-agent-protocol.md +0 -110
- package/docs/contracts/implement-ticket-flow.md +0 -625
- package/docs/contracts/init-telemetry.md +0 -132
- package/docs/contracts/injected-block-authenticity-model.md +0 -66
- package/docs/contracts/install-layout.md +0 -249
- package/docs/contracts/install-scopes.md +0 -82
- package/docs/contracts/installed-tools-lockfile.md +0 -144
- package/docs/contracts/installer-agent-mode.md +0 -137
- package/docs/contracts/iron-law-overrides.txt +0 -26
- package/docs/contracts/kernel-membership.md +0 -339
- package/docs/contracts/linear-ai-rules-inclusion.md +0 -143
- package/docs/contracts/linear-ai-three-layers.md +0 -130
- package/docs/contracts/linter-structural-model.md +0 -181
- package/docs/contracts/load-context-budget-model.md +0 -259
- package/docs/contracts/load-context-schema.md +0 -220
- package/docs/contracts/local-analytics.md +0 -160
- package/docs/contracts/local-knowledge-ingestion.md +0 -96
- package/docs/contracts/local-server-api.md +0 -134
- package/docs/contracts/low-impact-corpus-format.md +0 -95
- package/docs/contracts/mcp-beta-criteria.md +0 -130
- package/docs/contracts/mcp-cloud-scope.md +0 -355
- package/docs/contracts/mcp-discovery-phase-notice.md +0 -60
- package/docs/contracts/mcp-phase-1-scope.md +0 -272
- package/docs/contracts/mcp-registry-manifest.schema.json +0 -129
- package/docs/contracts/mcp-tool-inventory.md +0 -64
- package/docs/contracts/mcp-tool-stub-envelope.md +0 -78
- package/docs/contracts/measurement-baseline.md +0 -103
- package/docs/contracts/memory-visibility-v1.md +0 -160
- package/docs/contracts/mental-models.md +0 -336
- package/docs/contracts/migrate-command.md +0 -233
- package/docs/contracts/multi-tool-projection-fidelity.md +0 -134
- package/docs/contracts/namespace.md +0 -125
- package/docs/contracts/no-runtime-boundary.md +0 -61
- package/docs/contracts/one-off-script-lifecycle.md +0 -110
- package/docs/contracts/orchestration-dsl-v1.md +0 -153
- package/docs/contracts/package-self-orientation.md +0 -163
- package/docs/contracts/pilot/agent-authority.md +0 -24
- package/docs/contracts/pilot/direct-answers.md +0 -70
- package/docs/contracts/pilot/language-and-tone.md +0 -63
- package/docs/contracts/plain-language-surface.md +0 -117
- package/docs/contracts/prelaunch-diagnostics.md +0 -151
- package/docs/contracts/profile-system.md +0 -167
- package/docs/contracts/reasoning-discipline-protocol.md +0 -83
- package/docs/contracts/release-pr-gating.md +0 -151
- package/docs/contracts/release-sizing.md +0 -107
- package/docs/contracts/release-trunk-sync.md +0 -105
- package/docs/contracts/review-lens-schema.md +0 -64
- package/docs/contracts/roadmap-complexity-standard.md +0 -138
- package/docs/contracts/role-experience.md +0 -125
- package/docs/contracts/router-blending.md +0 -71
- package/docs/contracts/rule-classification.md +0 -171
- package/docs/contracts/rule-interactions.md +0 -132
- package/docs/contracts/rule-interactions.yml +0 -260
- package/docs/contracts/rule-priority-hierarchy.md +0 -88
- package/docs/contracts/rule-router.md +0 -287
- package/docs/contracts/safety-model.md +0 -129
- package/docs/contracts/session-profile-overlay.md +0 -157
- package/docs/contracts/settings-api.md +0 -264
- package/docs/contracts/settings-gui-agent-mode.schema.json +0 -128
- package/docs/contracts/settings-sync-yaml-subset.md +0 -139
- package/docs/contracts/skill-bundled-assets.md +0 -62
- package/docs/contracts/skill-discovery.md +0 -80
- package/docs/contracts/skill-distribution-channels.md +0 -66
- package/docs/contracts/skill-domains.md +0 -144
- package/docs/contracts/skill-dry-run.md +0 -47
- package/docs/contracts/skill-family-map.yml +0 -915
- package/docs/contracts/smoke-contracts.md +0 -144
- package/docs/contracts/subagent-boundary.md +0 -59
- package/docs/contracts/surface-agent-contracts.md +0 -153
- package/docs/contracts/surface-matrix.md +0 -108
- package/docs/contracts/surface-tiers.md +0 -81
- package/docs/contracts/telegraph-telemetry.md +0 -83
- package/docs/contracts/ticket-bundle-format.md +0 -233
- package/docs/contracts/tier-3-contrib-plugin.md +0 -137
- package/docs/contracts/trust-and-safety.md +0 -144
- package/docs/contracts/ui-stack-extension.md +0 -237
- package/docs/contracts/ui-track-flow.md +0 -329
- package/docs/contracts/universal-skills.md +0 -91
- package/docs/contracts/user-type-schema.md +0 -146
- package/docs/contracts/value-dashboard-spec.md +0 -378
- package/docs/contracts/value-report-schema.md +0 -168
- package/docs/contracts/workflow-packs.md +0 -121
- package/docs/contracts/workspace-boundary.md +0 -84
- package/docs/contracts/workspace-documents.md +0 -144
- package/docs/contracts/write-engine.md +0 -182
- package/docs/cookbook.md +0 -152
- package/docs/customization.md +0 -685
- package/docs/decisions/ADR-001-kernel-swap-deferred.md +0 -109
- package/docs/decisions/ADR-002-kernel-bucket-overrides.md +0 -135
- package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +0 -137
- package/docs/decisions/ADR-004-rule-governance-pruning.md +0 -240
- package/docs/decisions/ADR-005-subagent-worktrees.md +0 -120
- package/docs/decisions/ADR-006-skill-tools-python-pilot.md +0 -114
- package/docs/decisions/ADR-007-agent-discovery-scopes.md +0 -371
- package/docs/decisions/ADR-008-installed-tools-manifest.md +0 -160
- package/docs/decisions/ADR-009-event4u-namespace.md +0 -188
- package/docs/decisions/ADR-010-profile-pack-preset-boundary.md +0 -168
- package/docs/decisions/ADR-011-domain-pack-readiness.md +0 -213
- package/docs/decisions/ADR-012-typescript-cli-shell.md +0 -162
- package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +0 -342
- package/docs/decisions/ADR-014-gui-framework-choice.md +0 -136
- package/docs/decisions/ADR-015-discovery-manifest-contract.md +0 -146
- package/docs/decisions/ADR-016-installer-architecture.md +0 -189
- package/docs/decisions/ADR-017-monorepo-physical-layout.md +0 -261
- package/docs/decisions/ADR-018-trust-and-safety-layer.md +0 -159
- package/docs/decisions/ADR-019-router-json-dist-location.md +0 -124
- package/docs/decisions/ADR-020-global-only-consumer-scope.md +0 -213
- package/docs/decisions/ADR-021-deployment-shape.md +0 -153
- package/docs/decisions/ADR-022-daily-workspace-decomposition.md +0 -140
- package/docs/decisions/ADR-023-host-agent-protocol.md +0 -129
- package/docs/decisions/ADR-024-workspace-v0-feature-floor.md +0 -126
- package/docs/decisions/ADR-025-workspace-chrome.md +0 -119
- package/docs/decisions/ADR-026-explain-mode-translation.md +0 -117
- package/docs/decisions/ADR-027-changelog-machine-vs-manual.md +0 -129
- package/docs/decisions/ADR-028-root-layout.md +0 -147
- package/docs/decisions/ADR-029-multi-workspace-deferred.md +0 -122
- package/docs/decisions/ADR-030-claude-code-command-projection.md +0 -147
- package/docs/decisions/ADR-031-validation-severity-tiers-and-projection-roundtrip.md +0 -97
- package/docs/decisions/ADR-032-linked-projects-scope.md +0 -122
- package/docs/decisions/ADR-033-distribution-identity-npm-primary.md +0 -81
- package/docs/decisions/ADR-034-per-skill-model-recommendation-transport.md +0 -63
- package/docs/decisions/ADR-035-model-capability-tiers.md +0 -104
- package/docs/decisions/ADR-036-global-install-browser-wizard-handoff.md +0 -106
- package/docs/decisions/ADR-037-cost-profile-untangle.md +0 -117
- package/docs/decisions/ADR-038-canonical-settings-path.md +0 -96
- package/docs/decisions/ADR-039-claude-skills-untracked.md +0 -139
- package/docs/decisions/ADR-040-execution-model-projection-time-filtering.md +0 -244
- package/docs/decisions/ADR-041-controlled-command-verbs.md +0 -133
- package/docs/decisions/ADR-042-runtime-resolver-decision-gate.md +0 -113
- package/docs/decisions/ADR-043-monorepo-collapse-to-src-domains.md +0 -128
- package/docs/decisions/ADR-044-command-naming-scheme-hyphenated.md +0 -250
- package/docs/decisions/ADR-045-src-source-layout-and-profiles-as-views.md +0 -111
- package/docs/decisions/ADR-046-thin-command-principle.md +0 -93
- package/docs/decisions/ADR-047-framework-neutral-stack-adaptive-commands.md +0 -94
- package/docs/decisions/ADR-048-command-justification-rule.md +0 -106
- package/docs/decisions/ADR-049-configuration-trust-boundary.md +0 -132
- package/docs/decisions/ADR-050-workspace-vs-package-root-boundary.md +0 -121
- package/docs/decisions/ADR-051-uncondensed-source-container-relocation.md +0 -114
- package/docs/decisions/ADR-052-packages-removal-and-pack-home-migration.md +0 -86
- package/docs/decisions/ADR-053-agents-namespace-dual-role-resolution.md +0 -132
- package/docs/decisions/ADR-054-rule-adherence-decay-triggered-restate.md +0 -143
- package/docs/decisions/ADR-055-flow-layer-data-model.md +0 -235
- package/docs/decisions/ADR-056-unvalidated-video-adapters-disposition.md +0 -124
- package/docs/decisions/ADR-057-consolidation-evidence-gate-outcomes.md +0 -135
- package/docs/decisions/ADR-058-condensed-output-relocation-to-dist.md +0 -94
- package/docs/decisions/ADR-059-render-resume-filesystem-as-state.md +0 -161
- package/docs/decisions/ADR-060-comfyui-sandbox-model.md +0 -154
- package/docs/decisions/ADR-061-corpus-grounding-layer.md +0 -230
- package/docs/decisions/ADR-062-encrypt-at-rest-store-architecture.md +0 -121
- package/docs/decisions/ADR-063-append-jsonl-encryption-deferred.md +0 -83
- package/docs/decisions/ADR-064-append-jsonl-per-record-encryption.md +0 -113
- package/docs/decisions/ADR-065-tier3-inbox-handoff-v0.md +0 -86
- package/docs/decisions/ADR-066-skill-body-prerendering.md +0 -93
- package/docs/decisions/ADR-067-glama-registry-listing.md +0 -259
- package/docs/decisions/ADR-068-host-tier-detection.md +0 -90
- package/docs/decisions/ADR-069-prompt-renderer.md +0 -97
- package/docs/decisions/ADR-070-tier1-drive-loop.md +0 -94
- package/docs/decisions/ADR-071-launch-drive-integration.md +0 -95
- package/docs/decisions/ADR-072-codex-gemini-drive-configs.md +0 -90
- package/docs/decisions/ADR-073-drive-health-kill-switch.md +0 -81
- package/docs/decisions/ADR-074-drive-kill-switch-auto-recovery.md +0 -84
- package/docs/decisions/ADR-075-workspace-gui-drive.md +0 -83
- package/docs/decisions/ADR-076-workspace-multi-turn.md +0 -92
- package/docs/decisions/ADR-077-workspace-followup-gui.md +0 -70
- package/docs/decisions/ADR-078-drive-health-panel.md +0 -70
- package/docs/decisions/ADR-079-workspace-host-picker.md +0 -81
- package/docs/decisions/ADR-080-host-session-expired-410.md +0 -92
- package/docs/decisions/ADR-081-drive-health-reset-and-410-affordance.md +0 -71
- package/docs/decisions/ADR-082-410-one-click-relaunch.md +0 -58
- package/docs/decisions/ADR-083-session-thread-and-arbitrary-continuation.md +0 -85
- package/docs/decisions/ADR-084-drive-health-refresh-on-drive.md +0 -52
- package/docs/decisions/ADR-085-mcp-stdio-end-user-distribution-shape.md +0 -158
- package/docs/decisions/ADR-086-read-only-cross-agent-mcp-discovery-helper.md +0 -171
- package/docs/decisions/ADR-087-installer-e2e-test-strategy.md +0 -111
- package/docs/decisions/ADR-088-no-external-runtime-federation.md +0 -144
- package/docs/decisions/ADR-089-lean-local-plugin-install.md +0 -111
- package/docs/decisions/ADR-090-visibility-command-frontmatter-field.md +0 -95
- package/docs/decisions/ADR-091-split-meta-capability-packs.md +0 -113
- package/docs/decisions/ADR-092-defer-command-tier-alias-removal.md +0 -117
- package/docs/decisions/ADR-093-ai-council-config-user-global.md +0 -117
- package/docs/decisions/ADR-094-agent-memory-layer-removal.md +0 -94
- package/docs/decisions/ADR-095-workspace-boundary-contract.md +0 -108
- package/docs/decisions/ADR-096-analysis-workbench.md +0 -110
- package/docs/decisions/ADR-097-mission-recipe-privilege-boundary.md +0 -121
- package/docs/decisions/ADR-098-evidence-first-structure-discovery.md +0 -154
- package/docs/decisions/ADR-099-file-first-pattern-library.md +0 -87
- package/docs/decisions/ADR-100-global-knowledge-card-sharing.md +0 -140
- package/docs/decisions/ADR-101-ticket-bundle-emission.md +0 -109
- package/docs/decisions/ADR-102-ticket-handoff-paste-and-mcp.md +0 -72
- package/docs/decisions/ADR-103-global-knowledge-default-off-until-measured.md +0 -92
- package/docs/decisions/ADR-104-ai-council-config-global-only.md +0 -119
- package/docs/decisions/ADR-105-automatic-subagent-orchestration.md +0 -108
- package/docs/decisions/ADR-106-recursive-verification-benchmark-gate.md +0 -126
- package/docs/decisions/ADR-107-legal-domain-pack-adoption.md +0 -70
- package/docs/decisions/ADR-108-open-source-forever-no-commercial-tier.md +0 -46
- package/docs/decisions/ADR-109-subagent-v1-contract.md +0 -246
- package/docs/decisions/ADR-110-discipline-profile-resolution-locus.md +0 -110
- package/docs/decisions/ADR-111-canonical-glama-listing.md +0 -97
- package/docs/decisions/ADR-112-stdio-lite-stays-read-only.md +0 -92
- package/docs/decisions/ADR-113-ci-native-release-label-trigger.md +0 -201
- package/docs/decisions/ADR-114-commit-policy-iron-law-override.md +0 -85
- package/docs/decisions/ADR-115-command-cluster-consolidation-phase-4.md +0 -91
- package/docs/decisions/ADR-116-memory-tripwire-activation-path.md +0 -144
- package/docs/decisions/ADR-117-subagents-auto-default-on.md +0 -89
- package/docs/decisions/ADR-118-loop-engineering-boundaries.md +0 -162
- package/docs/decisions/ADR-119-global-knowledge-default-on.md +0 -104
- package/docs/decisions/ADR-120-council-chairman-mode.md +0 -70
- package/docs/decisions/ADR-121-knowledge-sensitivity-classes.md +0 -90
- package/docs/decisions/ADR-122-adversarial-verification-council.md +0 -166
- package/docs/decisions/ADR-123-runtime-security-scope-and-spawn-hardening.md +0 -142
- package/docs/decisions/ADR-200-python-to-typescript-migration.md +0 -203
- package/docs/decisions/ADR-rule-kernel-and-router.md +0 -133
- package/docs/decisions/INDEX.md +0 -136
- package/docs/deploy/connector-setup.md +0 -129
- package/docs/deploy/env-vars.md +0 -70
- package/docs/deploy/policy-cookbook.md +0 -130
- package/docs/deploy/quickstart.md +0 -112
- package/docs/deploy/small-team-recipe.md +0 -148
- package/docs/deploy/team-deployment-posture.md +0 -111
- package/docs/design/adversarial-council-eval.md +0 -106
- package/docs/design/council-vs-solo-baseline.md +0 -92
- package/docs/design/cross-model-parity-eval.md +0 -82
- package/docs/design/length-neutral-judge-rerun.md +0 -92
- package/docs/design/utilization-window-criteria.md +0 -51
- package/docs/development.md +0 -230
- package/docs/distribution/awesome-list-submission.md +0 -46
- package/docs/distribution/consumer-matrix.md +0 -96
- package/docs/distribution/launch-story-draft.md +0 -58
- package/docs/distribution/mcp-submission-checklist.md +0 -95
- package/docs/distribution/public-install-smoke.md +0 -68
- package/docs/distribution/registries.md +0 -117
- package/docs/distribution/registry-submissions.md +0 -85
- package/docs/distribution/telemetry-privacy.md +0 -128
- package/docs/distribution/telemetry-schema.md +0 -174
- package/docs/distribution/topics-equivalents-decay-policy.md +0 -51
- package/docs/end-to-end-walkthroughs.md +0 -165
- package/docs/enforcement-by-host.md +0 -44
- package/docs/examples/agent-user.example.md +0 -22
- package/docs/experiences/agency.md +0 -49
- package/docs/experiences/content_creator.md +0 -49
- package/docs/experiences/developer.md +0 -49
- package/docs/experiences/finance.md +0 -50
- package/docs/experiences/founder.md +0 -49
- package/docs/experiences/ops.md +0 -49
- package/docs/featured-commands.md +0 -27
- package/docs/featured-skills.md +0 -95
- package/docs/flows.md +0 -67
- package/docs/getting-started-by-role.md +0 -190
- package/docs/getting-started-laravel.md +0 -72
- package/docs/getting-started-local-stdio.md +0 -77
- package/docs/getting-started.md +0 -254
- package/docs/github-topics.md +0 -93
- package/docs/governance-advantage.md +0 -72
- package/docs/governance.md +0 -96
- package/docs/guides/cross-repo-linked-projects.md +0 -93
- package/docs/guides/cross-repo-retrieval.md +0 -61
- package/docs/guides/frontend-design-corpus-refresh.md +0 -83
- package/docs/guides/local-analytics.md +0 -125
- package/docs/guides/local-knowledge.md +0 -127
- package/docs/guides/skill-discovery.md +0 -71
- package/docs/guides/skill-preview.md +0 -71
- package/docs/hook-payload-capture.md +0 -221
- package/docs/install-friction-report.md +0 -66
- package/docs/installation.md +0 -959
- package/docs/maintainers/branch-protection.md +0 -105
- package/docs/maintainers/dev-mode.md +0 -106
- package/docs/maintainers/optional-media-deps.md +0 -50
- package/docs/maintainers/system-map.md +0 -85
- package/docs/mcp-registries.md +0 -94
- package/docs/mcp-server.md +0 -175
- package/docs/mcp.md +0 -147
- package/docs/media/proof-demo.cast +0 -14
- package/docs/media/proof-demo.gif +0 -0
- package/docs/migration/consumer-template-consumption-model.md +0 -145
- package/docs/migration/divergences/README.md +0 -55
- package/docs/migration/divergences/_template.md +0 -50
- package/docs/migration/divergences/bench-stats-float-precision.md +0 -72
- package/docs/migration/divergences/mcp-telemetry-node-sqlite.md +0 -61
- package/docs/migration/divergences/pack-mcp-content-gzip-body.md +0 -53
- package/docs/migration/divergences/src-scripts-build_cloud_bundle.md +0 -63
- package/docs/migration/divergences/src-scripts-check_memory.md +0 -91
- package/docs/migration/divergences/src-scripts-inventory_abstraction_budget.md +0 -65
- package/docs/migration/divergences/src-scripts-lint_marketplace.md +0 -57
- package/docs/migration/divergences/src-scripts-lint_mcp_registry_manifest.md +0 -70
- package/docs/migration/divergences/src-scripts-spotcheck_thin_root.md +0 -60
- package/docs/migration/divergences/src-scripts-validate_agent_settings.md +0 -58
- package/docs/migration/node-floor.md +0 -86
- package/docs/migration/v1-to-v2.md +0 -156
- package/docs/migration/yaml-roundtrip-spike.md +0 -163
- package/docs/migrations/commands-1.15.0.md +0 -117
- package/docs/parity/bench-external.json +0 -58
- package/docs/parity/bench.json +0 -41
- package/docs/parity/command-frontmatter.md +0 -60
- package/docs/parity/external-runtime.md +0 -46
- package/docs/personas.md +0 -178
- package/docs/positioning-evidence.md +0 -86
- package/docs/profiles.md +0 -108
- package/docs/proof.md +0 -176
- package/docs/quality.md +0 -98
- package/docs/readme-split-plan.md +0 -102
- package/docs/recruits/_template.md +0 -81
- package/docs/release-runbook.md +0 -141
- package/docs/role-experiences.md +0 -19
- package/docs/safety.md +0 -30
- package/docs/second-brain-scope.md +0 -116
- package/docs/self-review-gate.md +0 -65
- package/docs/setup/enterprise-and-offline.md +0 -201
- package/docs/setup/mcp-client-config.md +0 -358
- package/docs/setup/mcp-cloud-endpoints.md +0 -116
- package/docs/setup/mcp-cloud-registry-listing.md +0 -99
- package/docs/setup/mcp-cloud-setup.md +0 -183
- package/docs/setup/mcp-r2-bootstrap.md +0 -82
- package/docs/setup/mcp-server-docker.md +0 -101
- package/docs/setup/per-ide/aider.md +0 -48
- package/docs/setup/per-ide/antigravity.md +0 -68
- package/docs/setup/per-ide/augment.md +0 -89
- package/docs/setup/per-ide/claude-code.md +0 -97
- package/docs/setup/per-ide/claude-desktop.md +0 -207
- package/docs/setup/per-ide/cline.md +0 -43
- package/docs/setup/per-ide/codebuddy.md +0 -63
- package/docs/setup/per-ide/codex.md +0 -46
- package/docs/setup/per-ide/continue.md +0 -68
- package/docs/setup/per-ide/copilot.md +0 -80
- package/docs/setup/per-ide/cursor.md +0 -125
- package/docs/setup/per-ide/droid.md +0 -65
- package/docs/setup/per-ide/gemini-cli.md +0 -45
- package/docs/setup/per-ide/jetbrains.md +0 -76
- package/docs/setup/per-ide/kilocode.md +0 -66
- package/docs/setup/per-ide/kiro.md +0 -72
- package/docs/setup/per-ide/opencode.md +0 -62
- package/docs/setup/per-ide/qoder.md +0 -63
- package/docs/setup/per-ide/roocode.md +0 -68
- package/docs/setup/per-ide/trae.md +0 -63
- package/docs/setup/per-ide/warp.md +0 -63
- package/docs/setup/per-ide/windsurf.md +0 -109
- package/docs/setup/per-ide/zed.md +0 -73
- package/docs/showcase.md +0 -209
- package/docs/skill-duplication-findings.md +0 -91
- package/docs/skills-catalog.md +0 -265
- package/docs/skills-taxonomy.md +0 -90
- package/docs/spawn-site-policy.md +0 -72
- package/docs/succession.md +0 -80
- package/docs/threat-model.md +0 -29
- package/docs/troubleshooting.md +0 -155
- package/docs/ui-track-mental-model.md +0 -121
- package/docs/us-vs-the-category.md +0 -38
- package/docs/value.md +0 -86
- package/docs/walkthroughs/assets/workspace-role-grid.png +0 -0
- package/docs/walkthroughs/assets/workspace-session-started.png +0 -0
- package/docs/walkthroughs/assets/workspace-task-picker.png +0 -0
- package/docs/walkthroughs/daily-workspace-a11y.md +0 -87
- package/docs/walkthroughs/daily-workspace.md +0 -127
- package/docs/wedge/production-validator/README.md +0 -81
- package/docs/wedge/production-validator/first-run-check.sh +0 -42
- package/docs/wedge/production-validator/production-validator.md +0 -83
- package/docs/wizard.md +0 -173
|
@@ -0,0 +1,751 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* validate_reach_prescriptions.ts — mechanized supply-chain gate for the reach
|
|
4
|
+
* install prescriptions (road-to-internet-reach Phase 3, Steps 1 + 5).
|
|
5
|
+
*
|
|
6
|
+
* WHY THIS EXISTS. The roadmap's first draft asserted "every prescription
|
|
7
|
+
* passes the supply-chain-intake gate inline" with no mechanism. An honour
|
|
8
|
+
* system is not a differentiator, so the claim is machine-checked here: a
|
|
9
|
+
* prescription that is unpinned, points at a moving target, or names a tool
|
|
10
|
+
* nobody recorded an intake check for makes CI red.
|
|
11
|
+
*
|
|
12
|
+
* OFFLINE AND DETERMINISTIC BY CONSTRUCTION — a hard architectural constraint,
|
|
13
|
+
* not a preference. The Class A boundary (docs/contracts/no-runtime-boundary.md,
|
|
14
|
+
* ADR-124) forbids network access in the build path, and a lint that phones
|
|
15
|
+
* PyPI is a flaky lint. Registry existence and CVE state therefore come from
|
|
16
|
+
* the COMMITTED intake record (src/config/reach-prescriptions-intake.yml),
|
|
17
|
+
* never from a live fetch. This script spawns nothing and opens no socket.
|
|
18
|
+
*
|
|
19
|
+
* WHAT IT CHECKS
|
|
20
|
+
* (a) unpinned-install — an install string with no version specifier and
|
|
21
|
+
* no explicit `os-baseline:` sentinel.
|
|
22
|
+
* (b) moving-target-source — `latest` / `main` / `master` / `HEAD`, an
|
|
23
|
+
* `archive/` path, or a `.zip` / `.tgz` /
|
|
24
|
+
* `.tar.gz` / `.tar.xz` source.
|
|
25
|
+
* (c) unrecorded-package — a backend that prescribes an external install
|
|
26
|
+
* but has no entry in the intake record.
|
|
27
|
+
* plus pin-drift and package-name-mismatch (the registry pin and the package
|
|
28
|
+
* identifier must be the ones the intake record actually verified — this is
|
|
29
|
+
* the traceability half, which no schema can express), intake-record
|
|
30
|
+
* integrity (checklist fields, ISO dates, at least one recorded verification
|
|
31
|
+
* command), and the repo-wide grep gate below.
|
|
32
|
+
*
|
|
33
|
+
* GREP GATE SCOPE — deliberately narrow, and stated here because an unbounded
|
|
34
|
+
* "no unpinned install anywhere" sweep becomes a false-positive machine that
|
|
35
|
+
* gets suppressed and then means nothing:
|
|
36
|
+
* 1. `src/config/reach-*.yml` — every reach config file, in full.
|
|
37
|
+
* 2. `docs/**\/*.md` — reach material ONLY: the whole file when its
|
|
38
|
+
* name contains `reach`, otherwise just the heading sections whose heading
|
|
39
|
+
* text mentions reach (through to the next heading at the same or higher
|
|
40
|
+
* level). Non-reach documentation is out of scope on purpose.
|
|
41
|
+
* Two classes are rejected inside that scope: an unpinned install command, and
|
|
42
|
+
* a pipe-remote-to-shell instruction (`curl … | sh`, `wget … | bash`,
|
|
43
|
+
* `iwr … | iex`). The shipped-skill leg of the roadmap's scope list is absent
|
|
44
|
+
* because the Phase 0 verdict (`band: stop`) cancelled the skill — there is no
|
|
45
|
+
* `src/skills/internet-reach/` to scan.
|
|
46
|
+
*
|
|
47
|
+
* REUSE, NOT DUPLICATION. Schema validation belongs to
|
|
48
|
+
* check_reach_channels.ts; this script imports its loader and its validator
|
|
49
|
+
* for a pre-flight instead of re-implementing either. What it adds is the
|
|
50
|
+
* cross-file reasoning (registry ↔ intake record) and the surface sweep.
|
|
51
|
+
*
|
|
52
|
+
* Exit codes:
|
|
53
|
+
* 0 — clean.
|
|
54
|
+
* 1 — at least one violation.
|
|
55
|
+
* 3 — internal error: a target file is missing, unreadable, or unparseable.
|
|
56
|
+
*
|
|
57
|
+
* Invocation (from project root):
|
|
58
|
+
* tsx src/scripts/validate_reach_prescriptions.ts [<path-to-registry-yml>]
|
|
59
|
+
* [--intake <path>] [--quiet] [--help]
|
|
60
|
+
*
|
|
61
|
+
* The optional path argument is what lets the negative fixtures under
|
|
62
|
+
* `tests/fixtures/reach-prescriptions/` run through the same code path as the
|
|
63
|
+
* real registry. When it is given, the grep gate narrows to that one file (the
|
|
64
|
+
* fixture IS the surface under test); the full scope above is swept only for
|
|
65
|
+
* the real registry.
|
|
66
|
+
*/
|
|
67
|
+
import * as fs from 'node:fs';
|
|
68
|
+
import * as path from 'node:path';
|
|
69
|
+
import process from 'node:process';
|
|
70
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
71
|
+
|
|
72
|
+
import { parse as parseYaml } from 'yaml';
|
|
73
|
+
|
|
74
|
+
import {
|
|
75
|
+
RegistryLoadError,
|
|
76
|
+
SCHEMA_MESSAGE_MAX_CHARS,
|
|
77
|
+
excerpt_for_finding,
|
|
78
|
+
load_registry,
|
|
79
|
+
sanitizeParseError,
|
|
80
|
+
validate_file,
|
|
81
|
+
} from './check_reach_channels.js';
|
|
82
|
+
|
|
83
|
+
// The redaction helper moved one layer down into `check_reach_channels.ts`
|
|
84
|
+
// (both gates echo file-derived text, and the import already ran in this
|
|
85
|
+
// direction — the reverse would be a cycle). Re-exported unchanged so this
|
|
86
|
+
// module stays the surface its callers and tests already address.
|
|
87
|
+
export { EXCERPT_MAX_CHARS, REDACTIONS, excerpt_for_finding } from './check_reach_channels.js';
|
|
88
|
+
|
|
89
|
+
const _HERE = fileURLToPath(import.meta.url);
|
|
90
|
+
/** Repo root — two dirs up from src/scripts. */
|
|
91
|
+
const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
|
|
92
|
+
|
|
93
|
+
export const REGISTRY_PATH = path.join(ROOT, 'src', 'config', 'reach-channels.yml');
|
|
94
|
+
export const INTAKE_PATH = path.join(ROOT, 'src', 'config', 'reach-prescriptions-intake.yml');
|
|
95
|
+
|
|
96
|
+
/** Every finding carries the locator that makes it actionable without a grep. */
|
|
97
|
+
export interface Finding {
|
|
98
|
+
/** `channels[github].backends[gh].install.darwin` or `docs/x.md:42`. */
|
|
99
|
+
readonly locator: string;
|
|
100
|
+
/** Machine-stable violation class — tests assert on this, not on prose. */
|
|
101
|
+
readonly kind:
|
|
102
|
+
| 'schema'
|
|
103
|
+
| 'unpinned-install'
|
|
104
|
+
| 'moving-target-source'
|
|
105
|
+
| 'unrecorded-package'
|
|
106
|
+
| 'pin-drift'
|
|
107
|
+
| 'package-name-mismatch'
|
|
108
|
+
| 'intake-record'
|
|
109
|
+
| 'pipe-to-shell';
|
|
110
|
+
readonly message: string;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// --- pinning grammar -------------------------------------------------------
|
|
114
|
+
// Mirrors the install pattern in src/scripts/schemas/reach-channels.schema.json
|
|
115
|
+
// (that pattern is the pass/fail gate; these named checks say WHICH token made
|
|
116
|
+
// a string unacceptable, which a JSON-Schema `pattern` cannot report).
|
|
117
|
+
|
|
118
|
+
/** `name==1.2.3`, `node@22`, `--version 2.96.0`, or a bare `1.2.3` triple. */
|
|
119
|
+
const VERSION_PIN_RE =
|
|
120
|
+
/(?:==|@|=)v?\d+(?:\.\d+)*|--version[ =]v?\d+(?:\.\d+)*|\sv?\d+\.\d+\.\d+/;
|
|
121
|
+
|
|
122
|
+
/** Declared non-install: a tool the platform ships, with the reason inline. */
|
|
123
|
+
const OS_BASELINE_RE = /^os-baseline:\s*\S/;
|
|
124
|
+
|
|
125
|
+
/** Sources whose contents can change under a fixed reference. */
|
|
126
|
+
const MOVING_TARGET_PATTERNS: readonly (readonly [string, RegExp])[] = [
|
|
127
|
+
['latest', /\blatest\b/],
|
|
128
|
+
['main', /\bmain\b/],
|
|
129
|
+
['master', /\bmaster\b/],
|
|
130
|
+
['HEAD', /\bHEAD\b/],
|
|
131
|
+
['archive/ path', /archive\//],
|
|
132
|
+
['.zip archive', /\.zip\b/],
|
|
133
|
+
['.tgz archive', /\.tgz\b/],
|
|
134
|
+
['.tar.gz archive', /\.tar\.gz\b/],
|
|
135
|
+
['.tar.xz archive', /\.tar\.xz\b/],
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
/** A package-manager install invocation, in a command or a doc code span. */
|
|
139
|
+
const INSTALL_VERB_RE =
|
|
140
|
+
/\b(?:brew|pipx|pip3?|npm|pnpm|yarn|apt-get|apt|dnf|yum|apk|zypper|pacman|winget|choco|scoop|asdf|cargo|go|gem|uv|uvx)\s+(?:-{1,2}\S+\s+)*(?:install|add|get|i)\b/i;
|
|
141
|
+
|
|
142
|
+
/** `curl … | sh` and relatives — fetch straight into an interpreter. */
|
|
143
|
+
const PIPE_TO_SHELL_RE =
|
|
144
|
+
/\b(?:curl|wget|iwr|invoke-webrequest|fetch)\b[^|\n]*\|\s*(?:sudo\s+)?(?:\S*\/)?(?:sh|bash|zsh|dash|ksh|fish|pwsh|powershell|iex|invoke-expression|python3?|perl|ruby|node)\b/i;
|
|
145
|
+
|
|
146
|
+
const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
147
|
+
|
|
148
|
+
/** Checklist fields every `tools:` entry must carry, per supply-chain-intake. */
|
|
149
|
+
const INTAKE_CHECKLIST_FIELDS = [
|
|
150
|
+
'existence_verified',
|
|
151
|
+
'pinned',
|
|
152
|
+
'lockfile_note',
|
|
153
|
+
'cve_note',
|
|
154
|
+
] as const;
|
|
155
|
+
|
|
156
|
+
export function has_version_pin(command: string): boolean {
|
|
157
|
+
return VERSION_PIN_RE.test(command);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function is_os_baseline(command: string): boolean {
|
|
161
|
+
return OS_BASELINE_RE.test(command.trim());
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Every moving-target token present in the string, in declaration order. */
|
|
165
|
+
export function moving_targets(command: string): string[] {
|
|
166
|
+
return MOVING_TARGET_PATTERNS.filter(([, re]) => re.test(command)).map(([label]) => label);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// --- intake record ---------------------------------------------------------
|
|
170
|
+
|
|
171
|
+
export interface IntakeVerification {
|
|
172
|
+
readonly command: string;
|
|
173
|
+
readonly source?: string;
|
|
174
|
+
readonly observed?: string;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface IntakeTool {
|
|
178
|
+
readonly backend: string;
|
|
179
|
+
readonly pinned_version: string;
|
|
180
|
+
readonly packages: readonly { registry: string; package: string }[];
|
|
181
|
+
readonly intake: Record<string, string>;
|
|
182
|
+
readonly verified_on: string;
|
|
183
|
+
readonly verification: readonly IntakeVerification[];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface IntakeRecord {
|
|
187
|
+
readonly tools: readonly IntakeTool[];
|
|
188
|
+
/** Declared non-installs: tool name → true. */
|
|
189
|
+
readonly os_baseline: readonly { tool: string }[];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function as_object(value: unknown): Record<string, unknown> | null {
|
|
193
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
194
|
+
? (value as Record<string, unknown>)
|
|
195
|
+
: null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Parse the intake record. Throws RegistryLoadError when it is unusable. */
|
|
199
|
+
export function load_intake(intakePath: string = INTAKE_PATH): IntakeRecord {
|
|
200
|
+
if (!fs.existsSync(intakePath)) {
|
|
201
|
+
throw new RegistryLoadError(`intake record not found: ${intakePath}`);
|
|
202
|
+
}
|
|
203
|
+
let parsed: unknown;
|
|
204
|
+
try {
|
|
205
|
+
parsed = parseYaml(fs.readFileSync(intakePath, 'utf-8'));
|
|
206
|
+
} catch (err) {
|
|
207
|
+
// `sanitizeParseError`, not `String(err)`: a YAMLParseError stringifies
|
|
208
|
+
// with the offending source line and a caret, which would make
|
|
209
|
+
// `--intake <any-file>` an arbitrary-file-read oracle.
|
|
210
|
+
throw new RegistryLoadError(
|
|
211
|
+
`intake record is not parseable YAML: ${intakePath}: ${sanitizeParseError(err)}`,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const root = as_object(parsed);
|
|
215
|
+
if (!root) {
|
|
216
|
+
throw new RegistryLoadError(`intake record is not a YAML mapping: ${intakePath}`);
|
|
217
|
+
}
|
|
218
|
+
const tools = Array.isArray(root.tools) ? (root.tools as IntakeTool[]) : [];
|
|
219
|
+
const baseline = Array.isArray(root.os_baseline)
|
|
220
|
+
? (root.os_baseline as { tool: string }[])
|
|
221
|
+
: [];
|
|
222
|
+
return { tools, os_baseline: baseline };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Integrity of the record itself. A record whose entries are half-filled would
|
|
227
|
+
* silently satisfy the cross-checks below, so it is validated first.
|
|
228
|
+
*/
|
|
229
|
+
export function check_intake_record(intake: IntakeRecord): Finding[] {
|
|
230
|
+
const findings: Finding[] = [];
|
|
231
|
+
if (intake.tools.length === 0 && intake.os_baseline.length === 0) {
|
|
232
|
+
findings.push({
|
|
233
|
+
locator: 'reach-prescriptions-intake.yml',
|
|
234
|
+
kind: 'intake-record',
|
|
235
|
+
message: 'record declares neither `tools:` nor `os_baseline:` — nothing is recorded',
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
intake.tools.forEach((tool, index) => {
|
|
240
|
+
const at = `tools[${tool?.backend ?? index}]`;
|
|
241
|
+
if (!tool?.backend) {
|
|
242
|
+
findings.push({
|
|
243
|
+
locator: at,
|
|
244
|
+
kind: 'intake-record',
|
|
245
|
+
message: 'entry has no `backend:` — it cannot be matched to a registry backend',
|
|
246
|
+
});
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (!tool.pinned_version) {
|
|
250
|
+
findings.push({
|
|
251
|
+
locator: at,
|
|
252
|
+
kind: 'intake-record',
|
|
253
|
+
message: 'entry has no `pinned_version:` — the pin it verified is unknown',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (!Array.isArray(tool.packages) || tool.packages.length === 0) {
|
|
257
|
+
findings.push({
|
|
258
|
+
locator: at,
|
|
259
|
+
kind: 'intake-record',
|
|
260
|
+
message: 'entry declares no `packages:` — the verified package identity is unknown',
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
const checklist = as_object(tool.intake) ?? {};
|
|
264
|
+
for (const field of INTAKE_CHECKLIST_FIELDS) {
|
|
265
|
+
const value = checklist[field];
|
|
266
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
267
|
+
findings.push({
|
|
268
|
+
locator: `${at}.intake.${field}`,
|
|
269
|
+
kind: 'intake-record',
|
|
270
|
+
message: `supply-chain-intake checklist outcome \`${field}\` is missing or empty`,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (!ISO_DATE_RE.test(String(tool.verified_on ?? ''))) {
|
|
275
|
+
findings.push({
|
|
276
|
+
locator: `${at}.verified_on`,
|
|
277
|
+
kind: 'intake-record',
|
|
278
|
+
message: `\`verified_on\` must be a quoted ISO date (YYYY-MM-DD), got ${JSON.stringify(tool.verified_on ?? null)}`,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
const verifications = Array.isArray(tool.verification) ? tool.verification : [];
|
|
282
|
+
if (verifications.filter((entry) => Boolean(entry?.command)).length === 0) {
|
|
283
|
+
findings.push({
|
|
284
|
+
locator: `${at}.verification`,
|
|
285
|
+
kind: 'intake-record',
|
|
286
|
+
message:
|
|
287
|
+
'no `verification:` entry with a `command:` — the check is an assertion, not evidence',
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return findings;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// --- registry prescriptions ------------------------------------------------
|
|
296
|
+
|
|
297
|
+
export interface Prescription {
|
|
298
|
+
readonly channel: string;
|
|
299
|
+
readonly backend: string;
|
|
300
|
+
readonly platform: string;
|
|
301
|
+
readonly command: string;
|
|
302
|
+
readonly locator: string;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Flatten every install string in the registry. Defensive by design: a
|
|
307
|
+
* malformed registry is reported by the schema pre-flight, so anything
|
|
308
|
+
* unexpected here is skipped rather than thrown.
|
|
309
|
+
*/
|
|
310
|
+
export function extract_prescriptions(registry: unknown): Prescription[] {
|
|
311
|
+
const out: Prescription[] = [];
|
|
312
|
+
const root = as_object(registry);
|
|
313
|
+
const channels = Array.isArray(root?.channels) ? root.channels : [];
|
|
314
|
+
channels.forEach((rawChannel, channelIndex) => {
|
|
315
|
+
const channel = as_object(rawChannel);
|
|
316
|
+
if (!channel) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const channelId = typeof channel.id === 'string' ? channel.id : `#${channelIndex}`;
|
|
320
|
+
const backends = Array.isArray(channel.backends) ? channel.backends : [];
|
|
321
|
+
backends.forEach((rawBackend, backendIndex) => {
|
|
322
|
+
const backend = as_object(rawBackend);
|
|
323
|
+
if (!backend) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const backendId = typeof backend.id === 'string' ? backend.id : `#${backendIndex}`;
|
|
327
|
+
const install = as_object(backend.install) ?? {};
|
|
328
|
+
for (const [platform, command] of Object.entries(install)) {
|
|
329
|
+
if (typeof command !== 'string') {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
out.push({
|
|
333
|
+
channel: channelId,
|
|
334
|
+
backend: backendId,
|
|
335
|
+
platform,
|
|
336
|
+
command,
|
|
337
|
+
locator: `channels[${channelId}].backends[${backendId}].install.${platform}`,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
return out;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* The three roadmap rules plus the two traceability cross-checks.
|
|
347
|
+
*
|
|
348
|
+
* Checks are ordered so each string yields ONE primary finding: a moving-target
|
|
349
|
+
* source short-circuits the pin check (a pinned tarball URL is still a moving
|
|
350
|
+
* target), and an unpinned string short-circuits the pin-drift comparison
|
|
351
|
+
* (there is no pin to compare).
|
|
352
|
+
*/
|
|
353
|
+
export function check_prescriptions(registry: unknown, intake: IntakeRecord): Finding[] {
|
|
354
|
+
const findings: Finding[] = [];
|
|
355
|
+
const byBackend = new Map(intake.tools.map((tool) => [tool.backend, tool]));
|
|
356
|
+
const baseline = new Set(intake.os_baseline.map((entry) => entry?.tool).filter(Boolean));
|
|
357
|
+
|
|
358
|
+
for (const prescription of extract_prescriptions(registry)) {
|
|
359
|
+
const { command, locator, backend, channel } = prescription;
|
|
360
|
+
const recorded = byBackend.get(backend);
|
|
361
|
+
const declaredBaseline = baseline.has(backend);
|
|
362
|
+
|
|
363
|
+
const moving = moving_targets(command);
|
|
364
|
+
if (moving.length > 0) {
|
|
365
|
+
findings.push({
|
|
366
|
+
locator,
|
|
367
|
+
kind: 'moving-target-source',
|
|
368
|
+
message: `install source is a moving target (${moving.join(', ')}): ${JSON.stringify(excerpt_for_finding(command))} — pin an immutable release instead`,
|
|
369
|
+
});
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (is_os_baseline(command)) {
|
|
374
|
+
// A declared non-install. It still may not name a moving target
|
|
375
|
+
// (checked above) and still needs its tool declared as a baseline.
|
|
376
|
+
if (!declaredBaseline && !recorded) {
|
|
377
|
+
findings.push({
|
|
378
|
+
locator,
|
|
379
|
+
kind: 'unrecorded-package',
|
|
380
|
+
message: `backend \`${backend}\` (channel \`${channel}\`) claims an \`os-baseline:\` exemption but is not declared under \`os_baseline:\` in the intake record`,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (!has_version_pin(command)) {
|
|
387
|
+
findings.push({
|
|
388
|
+
locator,
|
|
389
|
+
kind: 'unpinned-install',
|
|
390
|
+
message: `install command carries no version specifier: ${JSON.stringify(excerpt_for_finding(command))} — pin it exactly, or declare an \`os-baseline:\` exemption with the reason`,
|
|
391
|
+
});
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// A real, pinned package install: it needs a recorded intake check.
|
|
396
|
+
if (!recorded) {
|
|
397
|
+
if (declaredBaseline) {
|
|
398
|
+
// Baseline tools may carry one pinned convenience prescription
|
|
399
|
+
// (e.g. a versioned Homebrew formula); the baseline declaration
|
|
400
|
+
// covers it.
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
findings.push({
|
|
404
|
+
locator,
|
|
405
|
+
kind: 'unrecorded-package',
|
|
406
|
+
message: `backend \`${backend}\` (channel \`${channel}\`) prescribes an external install but has no entry in the intake record — add one to src/config/reach-prescriptions-intake.yml (supply-chain-intake checklist) or the prescription cannot ship`,
|
|
407
|
+
});
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (!command.includes(recorded.pinned_version)) {
|
|
412
|
+
findings.push({
|
|
413
|
+
locator,
|
|
414
|
+
kind: 'pin-drift',
|
|
415
|
+
message: `install pins a version the intake record did not verify (record: ${recorded.pinned_version}): ${JSON.stringify(excerpt_for_finding(command))}`,
|
|
416
|
+
});
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const names = (recorded.packages ?? []).map((entry) => entry?.package).filter(Boolean);
|
|
421
|
+
if (names.length > 0 && !names.some((name) => command.includes(name))) {
|
|
422
|
+
findings.push({
|
|
423
|
+
locator,
|
|
424
|
+
kind: 'package-name-mismatch',
|
|
425
|
+
message: `install names no package the intake record verified (recorded: ${names.join(', ')}): ${JSON.stringify(excerpt_for_finding(command))}`,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return findings;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// --- grep gate over shipped reach surfaces ---------------------------------
|
|
434
|
+
|
|
435
|
+
/** A heading whose text mentions reach opens an in-scope docs section. */
|
|
436
|
+
const REACH_HEADING_RE = /^(#{1,6})\s+.*\breach\b/i;
|
|
437
|
+
const ANY_HEADING_RE = /^(#{1,6})\s+/;
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Line numbers (1-based) of a markdown file that count as reach material.
|
|
441
|
+
* Whole file when its name mentions reach; otherwise the reach heading
|
|
442
|
+
* sections only, each running to the next heading at the same or higher level.
|
|
443
|
+
*/
|
|
444
|
+
export function reach_scope_lines(relPath: string, text: string): Set<number> {
|
|
445
|
+
const lines = text.split('\n');
|
|
446
|
+
const inScope = new Set<number>();
|
|
447
|
+
if (/reach/i.test(path.basename(relPath))) {
|
|
448
|
+
lines.forEach((_line, index) => inScope.add(index + 1));
|
|
449
|
+
return inScope;
|
|
450
|
+
}
|
|
451
|
+
let openLevel: number | null = null;
|
|
452
|
+
lines.forEach((line, index) => {
|
|
453
|
+
const heading = ANY_HEADING_RE.exec(line);
|
|
454
|
+
if (heading) {
|
|
455
|
+
const level = (heading[1] ?? '#').length;
|
|
456
|
+
if (REACH_HEADING_RE.test(line)) {
|
|
457
|
+
openLevel = level;
|
|
458
|
+
} else if (openLevel !== null && level <= openLevel) {
|
|
459
|
+
openLevel = null;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
if (openLevel !== null) {
|
|
463
|
+
inScope.add(index + 1);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
return inScope;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Scan one surface's text. `scopeLines` restricts the sweep (docs sections);
|
|
471
|
+
* omit it to scan every line (config files, fixtures).
|
|
472
|
+
*
|
|
473
|
+
* Comments are scanned on purpose: a YAML comment or a doc paragraph telling a
|
|
474
|
+
* human to run `brew install <tool>` hands over the same unpinned artefact the
|
|
475
|
+
* command would, so exempting prose would leave the hazard reachable through
|
|
476
|
+
* the one channel this package actually ships — text a person reads.
|
|
477
|
+
*
|
|
478
|
+
* Every branch that echoes a line goes through `excerpt_for_finding` — a raw
|
|
479
|
+
* `line.trim()` here is what turned the positional path argument into a
|
|
480
|
+
* verbatim-content echo (`… | sh SECRET_EPS=…` printed the value).
|
|
481
|
+
*/
|
|
482
|
+
export function scan_surface_text(
|
|
483
|
+
relPath: string,
|
|
484
|
+
text: string,
|
|
485
|
+
scopeLines?: Set<number>,
|
|
486
|
+
): Finding[] {
|
|
487
|
+
const findings: Finding[] = [];
|
|
488
|
+
text.split('\n').forEach((line, index) => {
|
|
489
|
+
const lineNo = index + 1;
|
|
490
|
+
if (scopeLines && !scopeLines.has(lineNo)) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (PIPE_TO_SHELL_RE.test(line)) {
|
|
494
|
+
findings.push({
|
|
495
|
+
locator: `${relPath}:${lineNo}`,
|
|
496
|
+
kind: 'pipe-to-shell',
|
|
497
|
+
message: `pipes a remote fetch straight into an interpreter: ${excerpt_for_finding(line)} — download, inspect, then run a pinned artefact (supply-chain-intake § no pipe-to-shell)`,
|
|
498
|
+
});
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (INSTALL_VERB_RE.test(line) && !has_version_pin(line) && !/os-baseline:/.test(line)) {
|
|
502
|
+
findings.push({
|
|
503
|
+
locator: `${relPath}:${lineNo}`,
|
|
504
|
+
kind: 'unpinned-install',
|
|
505
|
+
message: `unpinned install command in a shipped reach surface: ${excerpt_for_finding(line)} — pin the version`,
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
return findings;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/** The explicit surface list. Kept in one function so the scope is auditable. */
|
|
513
|
+
export function collect_surfaces(root: string = ROOT): { abs: string; rel: string }[] {
|
|
514
|
+
const surfaces: { abs: string; rel: string }[] = [];
|
|
515
|
+
|
|
516
|
+
const configDir = path.join(root, 'src', 'config');
|
|
517
|
+
if (fs.existsSync(configDir)) {
|
|
518
|
+
for (const name of fs.readdirSync(configDir).sort()) {
|
|
519
|
+
if (/^reach-.*\.ya?ml$/.test(name)) {
|
|
520
|
+
surfaces.push({
|
|
521
|
+
abs: path.join(configDir, name),
|
|
522
|
+
rel: path.join('src', 'config', name),
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const docsDir = path.join(root, 'docs');
|
|
529
|
+
const walk = (dir: string): void => {
|
|
530
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) =>
|
|
531
|
+
a.name.localeCompare(b.name),
|
|
532
|
+
)) {
|
|
533
|
+
const abs = path.join(dir, entry.name);
|
|
534
|
+
if (entry.isDirectory()) {
|
|
535
|
+
walk(abs);
|
|
536
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
537
|
+
surfaces.push({ abs, rel: path.relative(root, abs) });
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
if (fs.existsSync(docsDir)) {
|
|
542
|
+
walk(docsDir);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return surfaces;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** Run the grep gate over the declared scope. */
|
|
549
|
+
export function scan_shipped_surfaces(root: string = ROOT): Finding[] {
|
|
550
|
+
const findings: Finding[] = [];
|
|
551
|
+
for (const surface of collect_surfaces(root)) {
|
|
552
|
+
let text: string;
|
|
553
|
+
try {
|
|
554
|
+
text = fs.readFileSync(surface.abs, 'utf-8');
|
|
555
|
+
} catch (err) {
|
|
556
|
+
throw new RegistryLoadError(
|
|
557
|
+
`surface unreadable: ${surface.rel}: ${sanitizeParseError(err)}`,
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
const isDoc = surface.rel.split(path.sep)[0] === 'docs';
|
|
561
|
+
findings.push(
|
|
562
|
+
...scan_surface_text(
|
|
563
|
+
surface.rel,
|
|
564
|
+
text,
|
|
565
|
+
isDoc ? reach_scope_lines(surface.rel, text) : undefined,
|
|
566
|
+
),
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
return findings;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// --- orchestration ---------------------------------------------------------
|
|
573
|
+
|
|
574
|
+
export interface RunOptions {
|
|
575
|
+
readonly registryPath?: string | undefined;
|
|
576
|
+
readonly intakePath?: string | undefined;
|
|
577
|
+
/** Grep-gate scope: the full surface list, or just the target registry. */
|
|
578
|
+
readonly surfaceRoot?: string | null | undefined;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Everything the CLI reports, as data. Throws RegistryLoadError for the exit-3
|
|
583
|
+
* class so an unusable file is never reported as "0 violations".
|
|
584
|
+
*/
|
|
585
|
+
export function run_checks(options: RunOptions = {}): Finding[] {
|
|
586
|
+
const registryPath = options.registryPath ?? REGISTRY_PATH;
|
|
587
|
+
const intakePath = options.intakePath ?? INTAKE_PATH;
|
|
588
|
+
const findings: Finding[] = [];
|
|
589
|
+
|
|
590
|
+
// Pre-flight: the schema gate owns shape validation (reuse, not a second
|
|
591
|
+
// implementation). Shape errors are surfaced, then the prescription checks
|
|
592
|
+
// run anyway on whatever is well-formed enough to read.
|
|
593
|
+
//
|
|
594
|
+
// `error.message` is file-derived — the Draft-07 `pattern` / `enum` rules
|
|
595
|
+
// quote the offending VALUE — so it goes through `excerpt_for_finding` like
|
|
596
|
+
// every other echo site. This was the last raw one: the two install-command
|
|
597
|
+
// paths above were already redacted while this message still printed
|
|
598
|
+
// `Value 'brew install curl SECRET=…' does not match /…/` verbatim.
|
|
599
|
+
for (const error of validate_file(registryPath).filter(
|
|
600
|
+
(finding) => finding.severity === 'error',
|
|
601
|
+
)) {
|
|
602
|
+
findings.push({
|
|
603
|
+
locator: error.path,
|
|
604
|
+
kind: 'schema',
|
|
605
|
+
message: `${error.rule}: ${excerpt_for_finding(error.message, SCHEMA_MESSAGE_MAX_CHARS)} (fix via \`task check-reach-channels\`)`,
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const registry = load_registry(registryPath);
|
|
610
|
+
const intake = load_intake(intakePath);
|
|
611
|
+
findings.push(...check_intake_record(intake));
|
|
612
|
+
findings.push(...check_prescriptions(registry, intake));
|
|
613
|
+
|
|
614
|
+
if (options.surfaceRoot === null) {
|
|
615
|
+
// Fixture run: the target file is the only surface under test.
|
|
616
|
+
const rel = path.relative(ROOT, registryPath) || registryPath;
|
|
617
|
+
findings.push(...scan_surface_text(rel, fs.readFileSync(registryPath, 'utf-8')));
|
|
618
|
+
} else {
|
|
619
|
+
findings.push(...scan_shipped_surfaces(options.surfaceRoot ?? ROOT));
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return findings;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
const HELP = `validate_reach_prescriptions — offline supply-chain gate for reach install prescriptions
|
|
626
|
+
|
|
627
|
+
Usage:
|
|
628
|
+
tsx src/scripts/validate_reach_prescriptions.ts [<registry.yml>] [options]
|
|
629
|
+
|
|
630
|
+
Options:
|
|
631
|
+
--intake <path> Intake record to read (default: src/config/reach-prescriptions-intake.yml)
|
|
632
|
+
--quiet Suppress the success line
|
|
633
|
+
--help This text
|
|
634
|
+
|
|
635
|
+
Checks (all offline — no network, no subprocess):
|
|
636
|
+
unpinned-install install string with no version specifier and no os-baseline: sentinel
|
|
637
|
+
moving-target-source latest / main / master / HEAD / archive path / .zip / .tgz / .tar.gz / .tar.xz
|
|
638
|
+
unrecorded-package backend prescribes an external install with no intake-record entry
|
|
639
|
+
pin-drift registry pin differs from the version the intake record verified
|
|
640
|
+
package-name-mismatch install names no package identifier the intake record verified
|
|
641
|
+
intake-record record entry missing a checklist outcome, an ISO date, or a verification command
|
|
642
|
+
pipe-to-shell a remote fetch piped into an interpreter (curl … | sh)
|
|
643
|
+
|
|
644
|
+
Grep-gate scope (narrow on purpose — an unbounded sweep becomes a false-positive machine):
|
|
645
|
+
1. src/config/reach-*.yml — in full.
|
|
646
|
+
2. docs/**/*.md — reach material only: the whole file when its name
|
|
647
|
+
contains "reach", otherwise only the heading sections whose heading text
|
|
648
|
+
mentions reach, each through to the next heading at the same or higher level.
|
|
649
|
+
Nothing else in the repo is scanned. There is no src/skills/internet-reach/ to
|
|
650
|
+
scan: the Phase 0 benchmark returned band: stop and the router skill was cancelled.
|
|
651
|
+
Comments and prose inside that scope count — text telling a human to run an
|
|
652
|
+
unpinned install hands over the same artefact the command would.
|
|
653
|
+
Passing a registry path narrows the gate to that one file (the fixture under test).
|
|
654
|
+
|
|
655
|
+
Exit codes: 0 clean · 1 violations · 3 unusable input (missing / unparseable file).
|
|
656
|
+
`;
|
|
657
|
+
|
|
658
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
659
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
660
|
+
process.stdout.write(HELP);
|
|
661
|
+
return 0;
|
|
662
|
+
}
|
|
663
|
+
const quiet = argv.includes('--quiet');
|
|
664
|
+
|
|
665
|
+
let intakePath: string | undefined;
|
|
666
|
+
const positional: string[] = [];
|
|
667
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
668
|
+
const arg = argv[index];
|
|
669
|
+
if (arg === undefined) {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (arg === '--intake') {
|
|
673
|
+
const value = argv[index + 1];
|
|
674
|
+
if (!value) {
|
|
675
|
+
process.stderr.write('validate_reach_prescriptions: --intake needs a path\n');
|
|
676
|
+
return 3;
|
|
677
|
+
}
|
|
678
|
+
intakePath = path.resolve(value);
|
|
679
|
+
index += 1;
|
|
680
|
+
} else if (arg.startsWith('--intake=')) {
|
|
681
|
+
intakePath = path.resolve(arg.slice('--intake='.length));
|
|
682
|
+
} else if (!arg.startsWith('-')) {
|
|
683
|
+
positional.push(arg);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
if (positional.length > 1) {
|
|
687
|
+
process.stderr.write(
|
|
688
|
+
'validate_reach_prescriptions: at most one registry path argument is accepted\n',
|
|
689
|
+
);
|
|
690
|
+
return 3;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
const registryPath = positional[0] ? path.resolve(positional[0]) : REGISTRY_PATH;
|
|
694
|
+
const relTarget = path.relative(ROOT, registryPath) || registryPath;
|
|
695
|
+
|
|
696
|
+
let findings: Finding[];
|
|
697
|
+
try {
|
|
698
|
+
findings = run_checks({
|
|
699
|
+
registryPath,
|
|
700
|
+
intakePath,
|
|
701
|
+
surfaceRoot: positional[0] ? null : ROOT,
|
|
702
|
+
});
|
|
703
|
+
} catch (err) {
|
|
704
|
+
if (err instanceof RegistryLoadError) {
|
|
705
|
+
process.stderr.write(`❌ validate_reach_prescriptions: ${err.message}\n`);
|
|
706
|
+
return 3;
|
|
707
|
+
}
|
|
708
|
+
throw err;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (findings.length > 0) {
|
|
712
|
+
process.stdout.write(
|
|
713
|
+
`❌ ${relTarget}: ${findings.length} prescription violation(s):\n`,
|
|
714
|
+
);
|
|
715
|
+
for (const finding of findings) {
|
|
716
|
+
process.stdout.write(` - [${finding.kind}] ${finding.locator}: ${finding.message}\n`);
|
|
717
|
+
}
|
|
718
|
+
return 1;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (!quiet) {
|
|
722
|
+
process.stdout.write(
|
|
723
|
+
`✅ ${relTarget}: every install prescription is pinned, intake-recorded, and free of pipe-to-shell (offline check).\n`,
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
return 0;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function _isCliEntry(): boolean {
|
|
730
|
+
if (!process.argv[1]) {
|
|
731
|
+
return false;
|
|
732
|
+
}
|
|
733
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
734
|
+
if (import.meta.url === argvUrl) {
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
// A symlinked invocation makes the raw URLs differ (import.meta.url is the
|
|
738
|
+
// resolved real path while argv[1] keeps the symlink path) — compare
|
|
739
|
+
// realpaths so the CLI still fires when run through a projection symlink.
|
|
740
|
+
try {
|
|
741
|
+
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
742
|
+
const argv = fs.realpathSync(path.resolve(process.argv[1]));
|
|
743
|
+
return here === argv;
|
|
744
|
+
} catch {
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (_isCliEntry()) {
|
|
750
|
+
process.exit(main());
|
|
751
|
+
}
|