@event4u/agent-config 14.10.0 → 14.11.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 +335 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/design.md +88 -0
- package/dist/agent-src/commands/project/analyze.md +47 -0
- package/dist/agent-src/commands/review/changes.md +67 -6
- package/dist/agent-src/commands/roadmap/create.md +49 -0
- package/dist/agent-src/commands/roadmap/next.md +27 -11
- package/dist/agent-src/commands/roadmap/process-full.md +14 -0
- package/dist/agent-src/commands/video/from-script.md +60 -3
- package/dist/agent-src/commands/video/stitch.md +14 -0
- package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/rules/active-remediation.md +3 -3
- package/dist/agent-src/rules/code-provenance.md +2 -2
- package/dist/agent-src/rules/context-hygiene.md +13 -33
- package/dist/agent-src/rules/council-availability.md +2 -2
- package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
- package/dist/agent-src/rules/design-fidelity.md +18 -0
- package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
- package/dist/agent-src/rules/evaluator-independence.md +56 -44
- package/dist/agent-src/rules/fix-what-you-see.md +9 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
- package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
- package/dist/agent-src/rules/playbook-precedence.md +105 -0
- package/dist/agent-src/rules/recurring-criticism.md +3 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
- package/dist/agent-src/rules/scale-discipline.md +24 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
- package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
- package/dist/agent-src/rules/ui-audit-gate.md +27 -15
- package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
- package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
- package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
- package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
- package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
- package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
- package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
- package/dist/agent-src/skills/brand/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
- package/dist/agent-src/skills/code-review/SKILL.md +11 -0
- package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
- package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
- package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
- package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
- package/dist/agent-src/skills/design-review/SKILL.md +79 -1
- package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
- package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
- package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
- package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
- package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
- package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
- package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
- package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
- package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
- package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
- package/dist/agent-src/skills/iconography/SKILL.md +3 -0
- package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
- package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
- package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
- package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
- package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
- package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
- package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
- package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
- package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
- package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
- package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
- package/dist/agent-src/skills/override-management/SKILL.md +3 -0
- package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
- package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
- package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
- package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
- package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
- package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
- package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
- package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
- package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
- package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
- package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
- package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
- package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
- package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
- package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
- package/dist/agent-src/skills/terraform/SKILL.md +3 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
- package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
- package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
- package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
- package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
- package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
- package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/playbook.md +75 -0
- package/dist/agent-src/templates/roadmaps.md +37 -0
- package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/dist/cli/commands/uiAudit.js +221 -0
- package/dist/cli/commands/uiAudit.js.map +1 -0
- package/dist/cli/commands/uiRender.js +206 -0
- package/dist/cli/commands/uiRender.js.map +1 -0
- package/dist/cli/main.js +22 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/content.js +64 -1
- package/dist/cli/mcp/content.js.map +1 -1
- package/dist/cli/mcp/dispatch.js +175 -10
- package/dist/cli/mcp/dispatch.js.map +1 -1
- package/dist/cli/registry.js +3 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
- package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
- package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
- package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
- package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
- package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +8 -6
- package/dist/cli-delegate/cmd_conformance.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +70 -9
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +359 -124
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +18 -8
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +16 -6
- package/dist/hooks/dispatch.js +2337 -1436
- package/dist/install/install.mjs +795 -708
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1685 -1250
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/lean_projection_mode.js +40 -0
- package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
- package/dist/scripts/_lib/scoped_projection.js +84 -0
- package/dist/scripts/_lib/scoped_projection.js.map +1 -1
- package/dist/scripts/_lib/ui_surface.js +89 -0
- package/dist/scripts/_lib/ui_surface.js.map +1 -0
- package/dist/scripts/condense.js +6 -10
- package/dist/scripts/condense.js.map +1 -1
- package/dist/scripts/project_thin_rules.js +40 -2
- package/dist/scripts/project_thin_rules.js.map +1 -1
- package/dist/server/schemas/settings.js +3 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/skillRanking.js +159 -0
- package/dist/shared/skillRanking.js.map +1 -0
- package/docs/contracts/provider-lifecycle.md +47 -18
- package/docs/contracts/settings-classes.md +14 -4
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
- package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
- package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
- package/docs/guidelines/design-antipatterns.md +4 -2
- package/docs/guidelines/design-asset-discipline.md +38 -0
- package/docs/guidelines/design-fidelity-mechanics.md +45 -29
- package/docs/guidelines/design-handover-extraction.md +35 -5
- package/docs/guidelines/design-modes.md +41 -1
- package/docs/guidelines/monorepo-antipatterns.md +141 -0
- package/llms.txt +50 -39
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
- package/src/config/agent-settings.template.yml +28 -0
- package/src/config/assurance-capability-registry.json +223 -0
- package/src/config/assurance-threshold-budget.json +65 -0
- package/src/config/ci-local-parity.yml +14 -0
- package/src/config/discovery/unassigned-artefacts.yml +2 -0
- package/src/config/dispatch-economy-metrics.json +4 -2
- package/src/config/evaluator-budgets.json +14 -14
- package/src/config/gate-coverage.yml +207 -8
- package/src/config/gate-violation-baselines.json +76 -72
- package/src/config/hook-latency-budget.json +1 -0
- package/src/config/hook-token-budget.json +137 -125
- package/src/config/pack-size-budget.json +4 -2
- package/src/config/quorum-attendance-budget.json +12 -4
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/config/rule-stub-ceilings.json +112 -91
- package/src/scripts/_cli/cmd_doctor.ts +15 -16
- package/src/scripts/_cli/doctor_install_mode.ts +49 -0
- package/src/scripts/_cli/doctor_overrides.ts +154 -0
- package/src/scripts/_dispatch.bash +17 -0
- package/src/scripts/_lib/as_of.ts +412 -0
- package/src/scripts/_lib/exec_evidence.ts +7 -0
- package/src/scripts/_lib/hook_settings.ts +33 -0
- package/src/scripts/_lib/host_listing_model.ts +192 -0
- package/src/scripts/_lib/lean_projection_mode.ts +44 -0
- package/src/scripts/_lib/mcp_bridge.ts +199 -0
- package/src/scripts/_lib/review_independence.ts +62 -10
- package/src/scripts/_lib/rule_injection.ts +239 -0
- package/src/scripts/_lib/run_checkpoint.ts +54 -1
- package/src/scripts/_lib/scoped_projection.ts +96 -0
- package/src/scripts/_lib/session_register.ts +44 -2
- package/src/scripts/_lib/skill_catalogue.ts +38 -2
- package/src/scripts/_lib/transcript_reads.ts +207 -0
- package/src/scripts/_lib/ui_authority.test.ts +251 -0
- package/src/scripts/_lib/ui_authority.ts +343 -0
- package/src/scripts/ai-video/adapters/fal.sh +8 -3
- package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
- package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
- package/src/scripts/ai-video/adapters/kling.sh +10 -0
- package/src/scripts/ai-video/adapters/sora.sh +10 -0
- package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
- package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
- package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
- package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
- package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
- package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
- package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
- package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
- package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
- package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
- package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
- package/src/scripts/ai-video/smoke-trace.sh +450 -2
- package/src/scripts/ai-video/stitch.sh +191 -10
- package/src/scripts/ai-video/test-pipeline.sh +84 -6
- package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
- package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
- package/src/scripts/ai_council/clients.ts +3 -2
- package/src/scripts/ai_council/consensus.ts +63 -6
- package/src/scripts/ai_council/events_log.ts +46 -1
- package/src/scripts/ai_council/orchestrator.ts +103 -108
- package/src/scripts/ai_council/orchestrator_results.ts +166 -0
- package/src/scripts/ai_council/prompts.ts +12 -5
- package/src/scripts/ai_council/quorum.ts +82 -1
- package/src/scripts/ai_council/quorum_wiring.ts +82 -5
- package/src/scripts/ai_council/stance_tally.ts +22 -0
- package/src/scripts/bench_hook_latency.ts +62 -0
- package/src/scripts/build_proof.ts +12 -1
- package/src/scripts/capture_skill_catalogue.ts +21 -0
- package/src/scripts/check_always_budget.ts +2 -1
- package/src/scripts/check_augmentignore.ts +2 -1
- package/src/scripts/check_beta_review_markers.ts +2 -1
- package/src/scripts/check_composite_arming.ts +364 -0
- package/src/scripts/check_corpus_staleness.ts +2 -1
- package/src/scripts/check_council_pin_staleness.ts +3 -1
- package/src/scripts/check_enforcement_coverage.ts +116 -3
- package/src/scripts/check_enforcement_denominator.ts +365 -0
- package/src/scripts/check_gate_coverage.ts +2 -1
- package/src/scripts/check_hook_bundle_freshness.ts +13 -1
- package/src/scripts/check_knowledge_cards.ts +2 -1
- package/src/scripts/check_knowledge_pages.ts +3 -2
- package/src/scripts/check_memory.ts +2 -1
- package/src/scripts/check_no_automerge_key.ts +287 -0
- package/src/scripts/check_pack_conformance_fixture.ts +565 -0
- package/src/scripts/check_proposal.ts +2 -1
- package/src/scripts/check_reach_staleness.ts +2 -1
- package/src/scripts/check_release_adjacent_health.ts +2 -1
- package/src/scripts/check_release_pr_shape.ts +5 -0
- package/src/scripts/check_review_schema.ts +34 -1
- package/src/scripts/check_roadmap_trackable.ts +48 -3
- package/src/scripts/check_source_size_budget.ts +2 -1
- package/src/scripts/check_standing_payload_delta.ts +505 -0
- package/src/scripts/check_trigger_evals.ts +2 -1
- package/src/scripts/classify_change_risk.ts +281 -0
- package/src/scripts/compute_skill_tiers.ts +186 -0
- package/src/scripts/condense.ts +8 -13
- package/src/scripts/council_attendance_metrics.ts +183 -0
- package/src/scripts/council_cli.ts +10 -8
- package/src/scripts/council_parse_rate.ts +116 -0
- package/src/scripts/derive_playbooks.ts +406 -0
- package/src/scripts/design_slop_rules.test.ts +7 -0
- package/src/scripts/design_slop_rules.ts +56 -2
- package/src/scripts/dispatch_r2_reviewer.ts +16 -0
- package/src/scripts/frontend_corpus_hash.ts +116 -0
- package/src/scripts/grade_target_readiness.ts +478 -0
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +97 -16
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/design_pass_hook.ts +356 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
- package/src/scripts/hooks/rule_inject_hook.ts +318 -0
- package/src/scripts/hot_context_hook.ts +74 -7
- package/src/scripts/install.ts +40 -89
- package/src/scripts/lint_adapter_tier.ts +663 -0
- package/src/scripts/lint_archived_skills.ts +93 -0
- package/src/scripts/lint_budget_ownership.ts +2 -1
- package/src/scripts/lint_deterministic_time.ts +470 -0
- package/src/scripts/lint_framework_leakage.ts +5 -0
- package/src/scripts/lint_handoffs.ts +525 -1
- package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
- package/src/scripts/lint_marketplace.ts +88 -0
- package/src/scripts/lint_media_policy_linkage.ts +140 -1
- package/src/scripts/lint_one_off_age.ts +6 -1
- package/src/scripts/lint_override_kernel_guard.ts +87 -5
- package/src/scripts/lint_roadmap_complexity.ts +56 -0
- package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
- package/src/scripts/lint_rule_norm_pin.ts +321 -0
- package/src/scripts/lint_spawn_payload.ts +42 -5
- package/src/scripts/lint_symptom_intake.ts +2 -1
- package/src/scripts/mcp_parity_smoke.ts +30 -4
- package/src/scripts/mcp_render.ts +66 -1
- package/src/scripts/mcp_tool_fingerprint.ts +241 -0
- package/src/scripts/measure_risk_class_drift.ts +140 -0
- package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
- package/src/scripts/media/lib/adapter-common.sh +211 -1
- package/src/scripts/media/lib/adapter-contract.md +74 -6
- package/src/scripts/model_rule_injection.ts +907 -0
- package/src/scripts/project_thin_rules.ts +45 -2
- package/src/scripts/release.ts +66 -860
- package/src/scripts/release_drill.ts +59 -3
- package/src/scripts/release_env.ts +298 -0
- package/src/scripts/release_publication.ts +720 -0
- package/src/scripts/roadmap_context.ts +778 -0
- package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +39 -0
- package/src/scripts/schemas/ui-authority.schema.json +114 -0
- package/src/scripts/session_register_hook.ts +29 -3
- package/src/scripts/sessions_cli.ts +67 -3
- package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
- package/src/scripts/token_sink_report.ts +239 -0
- package/src/scripts/trigger_coverage.ts +122 -3
- package/src/scripts/update_counts.ts +7 -3
- package/src/scripts/validate_frontmatter.ts +66 -0
- package/src/server/schemas/settings.ts +5 -0
- package/src/shared/skillRanking.ts +183 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Rule-inject — the delivery twin of `skill-route`, with the opposite payload
|
|
4
|
+
* policy (`road-to-trigger-delivered-rule-bodies` Phase 1).
|
|
5
|
+
*
|
|
6
|
+
* BODIES, NEVER POINTERS — and the difference from its twin is deliberate
|
|
7
|
+
* rather than incidental. `skill_route_hook.ts:14` ships "POINTERS, NEVER
|
|
8
|
+
* BODIES" on this same slot, and it is right to: a skill is a thing the agent
|
|
9
|
+
* *invokes*, so naming it is enough. A rule is a thing the agent must already
|
|
10
|
+
* be *under*, and the only datum anyone has on pointer-shaped rule delivery is
|
|
11
|
+
* the 36.2 %-against-48 % run at `docs/CLAIMS.md:188-189`. Whatever that
|
|
12
|
+
* instrument's flaws — and ADR-202 closed it — it points one way.
|
|
13
|
+
*
|
|
14
|
+
* DEFAULT OFF, AND OFF MEANS ZERO BYTES. The concern registers on two slots but
|
|
15
|
+
* returns before reading the router unless `lean_projection.mode: delivery` is
|
|
16
|
+
* set. Under every shipped default it emits nothing, costs no injection budget,
|
|
17
|
+
* and leaves the standing corpus exactly as it is today. That is why its
|
|
18
|
+
* `hook-token-budget.json` row is registered against the per-prompt cap rather
|
|
19
|
+
* than a measured emission: there is no measured emission to register yet.
|
|
20
|
+
*
|
|
21
|
+
* ONE MATCHER, SHARED WITH THE OFFLINE MODEL. Everything about selection,
|
|
22
|
+
* ordering, capping and body loading comes from `_lib/rule_injection.ts`, which
|
|
23
|
+
* `model_rule_injection.ts` also imports. Step 0.5 states the reason in as many
|
|
24
|
+
* words: an experiment whose offline pricing and runtime delivery use different
|
|
25
|
+
* matchers measures nothing.
|
|
26
|
+
*
|
|
27
|
+
* ONCE PER SESSION PER RULE, RE-ARMED ON COMPACTION. A rule's body is injected
|
|
28
|
+
* the first time one of its triggers fires and not again, because the model
|
|
29
|
+
* already has it. Compaction is exactly the event that makes that false, so
|
|
30
|
+
* `pre_compact` clears the seen-set — the same pin-lost shape `language-mirror`
|
|
31
|
+
* uses. State lives under `agents/runtime/state/`, the class
|
|
32
|
+
* `context-hygiene.json` already occupies; no new state convention is created.
|
|
33
|
+
*
|
|
34
|
+
* NEVER BLOCKS. Every failure path returns 0: unreadable stdin, malformed JSON,
|
|
35
|
+
* missing router, unreadable body, unwritable state. The one non-zero exit is
|
|
36
|
+
* the host's advisory context channel (exit 2 + `decision: "warn"`), the same
|
|
37
|
+
* channel `ui-route-nudge` and `code-graph-nudge` already use on `pre_tool_use`
|
|
38
|
+
* with `severity: advisory` — a warn there is an injection, not a deny.
|
|
39
|
+
*
|
|
40
|
+
* HOST BOUNDARY, STATED RATHER THAN IMPLIED. `user_prompt_submit` and
|
|
41
|
+
* `pre_tool_use` are bound on a subset of hosts, and only `claude` honours a
|
|
42
|
+
* deny at all. On a host where neither slot is bound this concern cannot run,
|
|
43
|
+
* which is the whole reason the flip step 2.4 gates on is Claude-only. Run
|
|
44
|
+
* `agent-config hooks:status` for the host you are actually on.
|
|
45
|
+
*
|
|
46
|
+
* SUBAGENTS ARE OUT OF REACH, MEASURED. Neither slot fires inside a spawned
|
|
47
|
+
* child session and the `subagent_start` payload carries no prompt field — see
|
|
48
|
+
* `agents/evidence/investigations/subagent-start-payload-probe.md` (2026-08-23,
|
|
49
|
+
* claude 2.1.241, three verdicts). Delivery is therefore orchestrator-only, and
|
|
50
|
+
* no third binding is added.
|
|
51
|
+
*/
|
|
52
|
+
import * as fs from 'node:fs';
|
|
53
|
+
import * as path from 'node:path';
|
|
54
|
+
import process from 'node:process';
|
|
55
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
56
|
+
|
|
57
|
+
import { hookSectionEnabled, leanProjectionModeRaw } from '../_lib/hook_settings.js';
|
|
58
|
+
import { deliversBodies, normalizeLeanProjectionMode } from '../_lib/lean_projection_mode.js';
|
|
59
|
+
import {
|
|
60
|
+
loadRuleBody,
|
|
61
|
+
loadRouter,
|
|
62
|
+
matchTierRules,
|
|
63
|
+
selectForInjection,
|
|
64
|
+
} from '../_lib/rule_injection.js';
|
|
65
|
+
import { readHookStdin } from './hook_stdin.js';
|
|
66
|
+
|
|
67
|
+
const EXIT_ALLOW = 0;
|
|
68
|
+
const EXIT_WARN = 2;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Per-prompt injection ceiling, in UTF-8 BYTES.
|
|
72
|
+
*
|
|
73
|
+
* DERIVED, NOT PICKED: `model_rule_injection --corpus tests/eval/routing-matrix`
|
|
74
|
+
* measured the matched-body-token distribution over the frozen labelled corpus
|
|
75
|
+
* at p50 1,728 / p90 4,804 / p99 8,248 / max 12,957 exact-BPE tokens, and step
|
|
76
|
+
* 1.1 specifies "the p90 from 0.4, rounded to 500" — 4,804 rounds up to 5,000.
|
|
77
|
+
*
|
|
78
|
+
* BYTES rather than tokens, and the unit change is the point rather than a
|
|
79
|
+
* detail. `_lib/token_count.ts` resolves `js-tiktoken` at module load, so a
|
|
80
|
+
* token-capped concern drags a tokenizer into EVERY hook dispatch on every
|
|
81
|
+
* slot, for a concern that is default-OFF and emits nothing. Measured: 202 ms
|
|
82
|
+
* -> 196 ms on the `pre_tool_use` p95 when the concern is unbound entirely, and
|
|
83
|
+
* the CI latency gate went red on the branch that introduced it while passing
|
|
84
|
+
* on main. So the runtime cap is the same bound in the unit
|
|
85
|
+
* `hook-token-budget.json` already enforces — 5,000 tok at the ~4 bytes/token
|
|
86
|
+
* this corpus measures is 20,480 B, which is exactly this concern's registered
|
|
87
|
+
* row. Cap and budget row are now one number instead of two units.
|
|
88
|
+
*
|
|
89
|
+
* Re-run that command if the corpus or the bodies move; a cap copied from a
|
|
90
|
+
* stale measurement is worse than no cap, because it looks derived.
|
|
91
|
+
*/
|
|
92
|
+
export const CAP_BYTES = 20480;
|
|
93
|
+
|
|
94
|
+
/** Tools whose input names a file this concern can match path triggers against. */
|
|
95
|
+
export const FILE_TOOLS = new Set(['Write', 'Edit', 'NotebookEdit', 'Read', 'MultiEdit']);
|
|
96
|
+
|
|
97
|
+
type JsonObject = Record<string, unknown>;
|
|
98
|
+
|
|
99
|
+
function isObject(v: unknown): v is JsonObject {
|
|
100
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function str(o: JsonObject, ...keys: string[]): string | null {
|
|
104
|
+
for (const k of keys) {
|
|
105
|
+
const v = o[k];
|
|
106
|
+
if (typeof v === 'string' && v !== '') return v;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Workspace root the envelope points at, falling back to the process cwd. */
|
|
112
|
+
export function workspaceRoot(env: JsonObject): string {
|
|
113
|
+
return str(env, 'workspace', 'cwd', 'project_dir') ?? process.cwd();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── seen-set state ───────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
export interface SeenState {
|
|
119
|
+
rules: string[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function statePath(root: string, session: string): string {
|
|
123
|
+
const safe = session.replace(/[^A-Za-z0-9_-]/g, '_').slice(0, 80) || 'unknown';
|
|
124
|
+
return path.join(root, 'agents', 'runtime', 'state', 'rule-inject', `${safe}.json`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function readSeen(root: string, session: string): Set<string> {
|
|
128
|
+
try {
|
|
129
|
+
const raw = fs.readFileSync(statePath(root, session), 'utf-8');
|
|
130
|
+
const parsed = JSON.parse(raw) as SeenState;
|
|
131
|
+
return new Set(Array.isArray(parsed.rules) ? parsed.rules.map(String) : []);
|
|
132
|
+
} catch {
|
|
133
|
+
return new Set(); // fresh session, or a file nothing can parse
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function writeSeen(root: string, session: string, seen: Set<string>): void {
|
|
138
|
+
const p = statePath(root, session);
|
|
139
|
+
try {
|
|
140
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
141
|
+
const payload: SeenState = { rules: [...seen].sort() };
|
|
142
|
+
fs.writeFileSync(`${p}.tmp`, `${JSON.stringify(payload)}\n`, 'utf-8');
|
|
143
|
+
fs.renameSync(`${p}.tmp`, p);
|
|
144
|
+
} catch {
|
|
145
|
+
/* unwritable state must never fail a turn — worst case a re-injection */
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function clearSeen(root: string, session: string): void {
|
|
150
|
+
try {
|
|
151
|
+
fs.rmSync(statePath(root, session), { force: true });
|
|
152
|
+
} catch {
|
|
153
|
+
/* ignore */
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── payload extraction ───────────────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
/** The user's prompt, across the shapes the hosts use. */
|
|
160
|
+
export function extractPrompt(payload: JsonObject): string {
|
|
161
|
+
return str(payload, 'prompt', 'user_prompt', 'userPrompt', 'message', 'text') ?? '';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** The file path a file-touching tool call names, or `null`. */
|
|
165
|
+
export function extractFilePath(payload: JsonObject): string | null {
|
|
166
|
+
const ti = payload['tool_input'] ?? payload['toolInput'] ?? payload['input'];
|
|
167
|
+
if (!isObject(ti)) return null;
|
|
168
|
+
return str(ti, 'file_path', 'path', 'filePath', 'notebook_path');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── decision ─────────────────────────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
export interface Injection {
|
|
174
|
+
rules: string[];
|
|
175
|
+
bytes: number;
|
|
176
|
+
body: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Build the injection for one event, or `null` for silence.
|
|
181
|
+
*
|
|
182
|
+
* `prompt` drives keyword / phrase / command triggers; `openFiles` drives
|
|
183
|
+
* `path_prefix` / `file_pattern`. On the tool slot the prompt is deliberately
|
|
184
|
+
* empty, so a file event can only ever fire a path trigger — a tool call is not
|
|
185
|
+
* a restatement of the user's request and must not re-fire keyword rules.
|
|
186
|
+
*/
|
|
187
|
+
export function buildInjection(
|
|
188
|
+
root: string,
|
|
189
|
+
prompt: string,
|
|
190
|
+
openFiles: string[] | null,
|
|
191
|
+
command: string | null,
|
|
192
|
+
seen: Set<string>,
|
|
193
|
+
): Injection | null {
|
|
194
|
+
let router;
|
|
195
|
+
try {
|
|
196
|
+
router = loadRouter(root);
|
|
197
|
+
} catch {
|
|
198
|
+
return null; // no router — nothing to deliver, and never a failure
|
|
199
|
+
}
|
|
200
|
+
const matches = matchTierRules(router, prompt, openFiles, command).filter(
|
|
201
|
+
(m) => !seen.has(m.id),
|
|
202
|
+
);
|
|
203
|
+
if (matches.length === 0) return null;
|
|
204
|
+
const sel = selectForInjection(root, matches, CAP_BYTES);
|
|
205
|
+
const parts: string[] = [];
|
|
206
|
+
const ids: string[] = [];
|
|
207
|
+
for (const m of sel.selected) {
|
|
208
|
+
const body = loadRuleBody(root, m.id);
|
|
209
|
+
if (body === null) continue;
|
|
210
|
+
ids.push(m.id);
|
|
211
|
+
parts.push(`<rule id="${m.id}" tier="${m.tier}">\n${body.trim()}\n</rule>`);
|
|
212
|
+
}
|
|
213
|
+
if (ids.length === 0) return null;
|
|
214
|
+
return { rules: ids, bytes: sel.bytes, body: parts.join('\n\n') };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// ── main ─────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Whether the settings gate applies.
|
|
221
|
+
*
|
|
222
|
+
* Through the dispatcher the gate is absolute: no `lean_projection.mode:
|
|
223
|
+
* delivery`, no bytes. A DIRECT CLI invocation is a probe by definition — an
|
|
224
|
+
* operator piping an envelope into this file is asking to see what it would
|
|
225
|
+
* deliver — so there the mode defaults to on. `AGENT_CONFIG_REPLAY` re-imposes
|
|
226
|
+
* the gate, which is what keeps `bench_hook_injection` measuring the shipped
|
|
227
|
+
* default (zero bytes) rather than the probe.
|
|
228
|
+
*/
|
|
229
|
+
export function gateOpen(root: string, cliEntry: boolean): boolean {
|
|
230
|
+
if (deliversBodies(normalizeLeanProjectionMode(leanProjectionModeRaw(root)))) return true;
|
|
231
|
+
if (hookSectionEnabled(root, 'rule_inject')) return true;
|
|
232
|
+
return cliEntry && process.env['AGENT_CONFIG_REPLAY'] !== '1';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function main(argv: readonly string[] = process.argv.slice(2)): number {
|
|
236
|
+
let eventOverride: string | null = null;
|
|
237
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
238
|
+
if (argv[i] === '--event') {
|
|
239
|
+
i += 1;
|
|
240
|
+
eventOverride = argv[i] ?? null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
let env: JsonObject = {};
|
|
245
|
+
try {
|
|
246
|
+
const raw = readHookStdin();
|
|
247
|
+
const parsed = raw.trim() ? (JSON.parse(raw) as unknown) : {};
|
|
248
|
+
env = isObject(parsed) ? parsed : {};
|
|
249
|
+
} catch {
|
|
250
|
+
return EXIT_ALLOW; // malformed envelope — never block
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const root = workspaceRoot(env);
|
|
254
|
+
const payload = isObject(env['payload']) ? (env['payload'] as JsonObject) : env;
|
|
255
|
+
const slot = eventOverride ?? str(env, 'event') ?? 'user_prompt_submit';
|
|
256
|
+
const session = str(env, 'session_id', 'sessionId') ?? str(payload, 'session_id', 'sessionId') ?? 'unknown';
|
|
257
|
+
|
|
258
|
+
if (slot === 'pre_compact') {
|
|
259
|
+
clearSeen(root, session);
|
|
260
|
+
return EXIT_ALLOW; // re-arm is silent; the next turn re-injects
|
|
261
|
+
}
|
|
262
|
+
if (slot !== 'user_prompt_submit' && slot !== 'pre_tool_use') return EXIT_ALLOW;
|
|
263
|
+
if (!gateOpen(root, _isCliEntry())) return EXIT_ALLOW;
|
|
264
|
+
|
|
265
|
+
let prompt = '';
|
|
266
|
+
let openFiles: string[] | null = null;
|
|
267
|
+
let command: string | null = null;
|
|
268
|
+
if (slot === 'user_prompt_submit') {
|
|
269
|
+
prompt = extractPrompt(payload);
|
|
270
|
+
if (prompt === '') return EXIT_ALLOW;
|
|
271
|
+
const m = /^\s*(\/[A-Za-z0-9:_-]+)/.exec(prompt);
|
|
272
|
+
command = m ? (m[1] as string) : null;
|
|
273
|
+
} else {
|
|
274
|
+
const tool = str(payload, 'tool_name', 'toolName', 'tool');
|
|
275
|
+
if (tool === null || !FILE_TOOLS.has(tool)) return EXIT_ALLOW;
|
|
276
|
+
const fp = extractFilePath(payload);
|
|
277
|
+
if (fp === null) return EXIT_ALLOW;
|
|
278
|
+
openFiles = [fp];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const seen = readSeen(root, session);
|
|
282
|
+
const injection = buildInjection(root, prompt, openFiles, command, seen);
|
|
283
|
+
if (injection === null) return EXIT_ALLOW; // silence is the default
|
|
284
|
+
|
|
285
|
+
for (const id of injection.rules) seen.add(id);
|
|
286
|
+
writeSeen(root, session, seen);
|
|
287
|
+
|
|
288
|
+
process.stdout.write(
|
|
289
|
+
`${JSON.stringify({
|
|
290
|
+
decision: 'warn',
|
|
291
|
+
reason: `rule-inject: ${injection.rules.length} rule body/bodies on ${slot} (${injection.bytes} B)`,
|
|
292
|
+
additional_context: injection.body,
|
|
293
|
+
})}\n`,
|
|
294
|
+
);
|
|
295
|
+
return EXIT_WARN;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Bundle-safety: never auto-run when inlined into an esbuild bundle, where
|
|
299
|
+
// every module shares the bundle's `import.meta.url`.
|
|
300
|
+
declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
|
|
301
|
+
function _isCliEntry(): boolean {
|
|
302
|
+
if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
|
|
303
|
+
if (process.argv[1] === undefined) return false;
|
|
304
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
305
|
+
if (import.meta.url === argvUrl) return true;
|
|
306
|
+
try {
|
|
307
|
+
return (
|
|
308
|
+
fs.realpathSync(fileURLToPath(import.meta.url)) ===
|
|
309
|
+
fs.realpathSync(path.resolve(process.argv[1]))
|
|
310
|
+
);
|
|
311
|
+
} catch {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (_isCliEntry()) {
|
|
317
|
+
process.exit(main());
|
|
318
|
+
}
|
|
@@ -36,6 +36,7 @@ import process from 'node:process';
|
|
|
36
36
|
import { fileURLToPath } from 'node:url';
|
|
37
37
|
|
|
38
38
|
import { hardenedSpawnEnv } from './_lib/spawn_env.js';
|
|
39
|
+
import { computeRereads } from './_lib/transcript_reads.js';
|
|
39
40
|
import { redact_low_impact_entry } from './ai_council/redact_low_impact_entry.js';
|
|
40
41
|
import { readHookStdin } from './hooks/hook_stdin.js';
|
|
41
42
|
|
|
@@ -57,6 +58,7 @@ const MAX_OPEN_VERIFICATIONS = 3;
|
|
|
57
58
|
const THREAD_SNIPPET_CHARS = 200;
|
|
58
59
|
const CHANGE_SNIPPET_CHARS = 120;
|
|
59
60
|
const KEY_FACTS_CHARS = 600;
|
|
61
|
+
const MAX_REREAD_LINES = 3; // advisory, not an inventory — see _reread_lines
|
|
60
62
|
|
|
61
63
|
const VERIFICATION_RE = /\b(fail(ing|ed|ure)?|error|exit[= ][1-9]|red\b|broken)\b/i;
|
|
62
64
|
|
|
@@ -161,11 +163,55 @@ function _word_count(text: string): number {
|
|
|
161
163
|
return text.split(/\s+/).filter((w) => w.length > 0).length;
|
|
162
164
|
}
|
|
163
165
|
|
|
166
|
+
// ---------------------------------------------------------------------
|
|
167
|
+
// re-read advisory (road-to-role-scoped-spawn-profiles Phase 3 Steps 4-5)
|
|
168
|
+
// ---------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Files this leg read more than once, as advisory lines for the cache.
|
|
172
|
+
*
|
|
173
|
+
* Phase 3 Step 4 of `road-to-role-scoped-spawn-profiles` requires the
|
|
174
|
+
* suppression to ride THIS surface rather than arrive as a second artefact,
|
|
175
|
+
* and Step 5 requires it to stay advice: there is no refuse branch anywhere
|
|
176
|
+
* below, and there is no code path that returns a deny on a re-read condition.
|
|
177
|
+
* The output is three lines in a markdown cache; the next leg may ignore it.
|
|
178
|
+
*
|
|
179
|
+
* **Why the path is relativised, and why an outside path is dropped rather
|
|
180
|
+
* than shortened.** The privacy floor
|
|
181
|
+
* ({@link _redact_lines} → `redact_low_impact_entry`) drops any line carrying
|
|
182
|
+
* a project-rooted absolute path, so emitting `/Users/...` would produce a
|
|
183
|
+
* silently empty section — the feature would look implemented and do nothing.
|
|
184
|
+
* Relativising to the workspace root keeps the line inside the floor. A path
|
|
185
|
+
* OUTSIDE the root cannot be relativised without `../` escapes that re-reveal
|
|
186
|
+
* the layout, and it is another project's business in any case, so it is
|
|
187
|
+
* dropped entirely.
|
|
188
|
+
*
|
|
189
|
+
* Fail-silent: no transcript path, an unreadable one, or a malformed leg all
|
|
190
|
+
* yield `[]`. This is a cache, and a cache that throws is worse than a cache
|
|
191
|
+
* that is short.
|
|
192
|
+
*/
|
|
193
|
+
export function _reread_lines(transcriptPath: string | null, root: string): string[] {
|
|
194
|
+
if (!transcriptPath) return [];
|
|
195
|
+
const result = computeRereads([transcriptPath]);
|
|
196
|
+
const lines: string[] = [];
|
|
197
|
+
for (const f of result.files) {
|
|
198
|
+
if (lines.length >= MAX_REREAD_LINES) break;
|
|
199
|
+
const rel = path.relative(root, f.file_path);
|
|
200
|
+
if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) continue;
|
|
201
|
+
lines.push(`${rel} — read ${f.total_reads}x this leg (${f.duplicate_reads} re-read)`);
|
|
202
|
+
}
|
|
203
|
+
return lines;
|
|
204
|
+
}
|
|
205
|
+
|
|
164
206
|
// ---------------------------------------------------------------------
|
|
165
207
|
// stop — deterministic write
|
|
166
208
|
// ---------------------------------------------------------------------
|
|
167
209
|
|
|
168
|
-
export function build_hot_context(
|
|
210
|
+
export function build_hot_context(
|
|
211
|
+
root: string,
|
|
212
|
+
now: Date = new Date(),
|
|
213
|
+
transcriptPath: string | null = null,
|
|
214
|
+
): string {
|
|
169
215
|
const session = _latest_session_entries(_read_history(root));
|
|
170
216
|
|
|
171
217
|
const userPrompts = session.filter((e) => e.t === 'user_prompt' && e.text);
|
|
@@ -188,20 +234,36 @@ export function build_hot_context(root: string, now: Date = new Date()): string
|
|
|
188
234
|
);
|
|
189
235
|
const lastStop = String(stops[stops.length - 1]?.text ?? '');
|
|
190
236
|
const keyFacts = _redact_lines(lastStop ? [_snippet(lastStop, KEY_FACTS_CHARS)] : []);
|
|
237
|
+
const rereads = _redact_lines(_reread_lines(transcriptPath, root));
|
|
191
238
|
|
|
192
239
|
const droppedTotal =
|
|
193
|
-
activeThreads.dropped +
|
|
240
|
+
activeThreads.dropped +
|
|
241
|
+
recentChanges.dropped +
|
|
242
|
+
openVerifications.dropped +
|
|
243
|
+
keyFacts.dropped +
|
|
244
|
+
rereads.dropped;
|
|
194
245
|
|
|
195
246
|
// Assemble; trim lowest-priority sections first until under the word cap.
|
|
196
247
|
// Priority (highest kept longest): Key Facts > Active Threads >
|
|
197
|
-
// Open Verifications > Recent Changes.
|
|
248
|
+
// Open Verifications > Recent Changes > Re-Read Advisory.
|
|
249
|
+
//
|
|
250
|
+
// The advisory sits LAST on purpose. It is the only section that is a
|
|
251
|
+
// suggestion rather than a record of what happened, so when the 400-word
|
|
252
|
+
// cap bites it is the one whose loss costs nothing.
|
|
198
253
|
const sections: Array<{ title: string; items: string[] }> = [
|
|
199
254
|
{ title: 'Key Facts', items: keyFacts.kept },
|
|
200
255
|
{ title: 'Active Threads', items: activeThreads.kept },
|
|
201
256
|
{ title: 'Open Verifications', items: openVerifications.kept },
|
|
202
257
|
{ title: 'Recent Changes', items: recentChanges.kept },
|
|
258
|
+
{ title: 'Re-Read Advisory', items: rereads.kept },
|
|
259
|
+
];
|
|
260
|
+
const trimOrder = [
|
|
261
|
+
'Re-Read Advisory',
|
|
262
|
+
'Recent Changes',
|
|
263
|
+
'Open Verifications',
|
|
264
|
+
'Active Threads',
|
|
265
|
+
'Key Facts',
|
|
203
266
|
];
|
|
204
|
-
const trimOrder = ['Recent Changes', 'Open Verifications', 'Active Threads', 'Key Facts'];
|
|
205
267
|
|
|
206
268
|
const render = (): string => {
|
|
207
269
|
const lines: string[] = [
|
|
@@ -240,9 +302,9 @@ export function build_hot_context(root: string, now: Date = new Date()): string
|
|
|
240
302
|
return text;
|
|
241
303
|
}
|
|
242
304
|
|
|
243
|
-
function _write_hot_context(root: string): void {
|
|
305
|
+
function _write_hot_context(root: string, transcriptPath: string | null = null): void {
|
|
244
306
|
const target = _hot_context_path(root);
|
|
245
|
-
const text = build_hot_context(root);
|
|
307
|
+
const text = build_hot_context(root, new Date(), transcriptPath);
|
|
246
308
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
247
309
|
const tmp = `${target}.tmp-${process.pid}`;
|
|
248
310
|
fs.writeFileSync(tmp, text, { encoding: 'utf-8' });
|
|
@@ -392,7 +454,12 @@ export function main(): number {
|
|
|
392
454
|
// one rebuild and can never produce a worse cache than the older one it
|
|
393
455
|
// replaces. It emits nothing — the restore side is unchanged.
|
|
394
456
|
if (event === 'stop' || event === 'session_end' || event === 'pre_compact') {
|
|
395
|
-
|
|
457
|
+
// Claude Code puts the leg's own transcript on the stop payload;
|
|
458
|
+
// the camelCase alias is defensive, matching how the subagent
|
|
459
|
+
// ledger reads `last_assistant_message`. Absent on other hosts,
|
|
460
|
+
// where the advisory is simply empty.
|
|
461
|
+
const tp = payload.transcript_path ?? payload.transcriptPath;
|
|
462
|
+
_write_hot_context(root, typeof tp === 'string' && tp.length > 0 ? tp : null);
|
|
396
463
|
} else if (event === 'session_start') {
|
|
397
464
|
const source = String(payload.source ?? '');
|
|
398
465
|
const decision = restore_hot_context(root, source);
|
package/src/scripts/install.ts
CHANGED
|
@@ -74,6 +74,7 @@ import type * as YamlModule from 'yaml';
|
|
|
74
74
|
import { build_merge_entries } from './_lib/json_pointers.js';
|
|
75
75
|
import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
|
|
76
76
|
import * as installed_lock from './_lib/installed_lock.js';
|
|
77
|
+
import * as mcp_bridge from './_lib/mcp_bridge.js';
|
|
77
78
|
import * as scoped_projection from './_lib/scoped_projection.js';
|
|
78
79
|
import * as surface_tiers from './_lib/surface_tiers.js';
|
|
79
80
|
import * as global_deploy_inventory from './_lib/global_deploy_inventory.js';
|
|
@@ -1115,6 +1116,18 @@ function ensure_claude_bridge(project_root: string, force: boolean): Record<stri
|
|
|
1115
1116
|
return merge_json_file(target, bridge, force || healed.length > 0, '.claude/settings.json');
|
|
1116
1117
|
}
|
|
1117
1118
|
|
|
1119
|
+
// `.mcp.json` registration + the skill-tier projection lever live in
|
|
1120
|
+
// `_lib/mcp_bridge.ts`; only the call sites are here (see that module's header
|
|
1121
|
+
// for why). Names are forwarded so the export surface is unchanged.
|
|
1122
|
+
const ensure_mcp_bridge = mcp_bridge.makeEnsureMcpBridge(merge_json_file);
|
|
1123
|
+
const _resolve_tier_b = mcp_bridge.resolveTierB;
|
|
1124
|
+
const _tier_b_advisory = mcp_bridge.tierBAdvisory;
|
|
1125
|
+
const _prune_tier_b_modules = (
|
|
1126
|
+
dr: Record<string, DeployResult>,
|
|
1127
|
+
tier_b: ReadonlySet<string>,
|
|
1128
|
+
): [number, Record<string, DeployResult>] =>
|
|
1129
|
+
_prune_modules_by(dr, mcp_bridge.tierBPrunePredicate(tier_b));
|
|
1130
|
+
|
|
1118
1131
|
const CURSOR_DISPATCHER_BINDINGS: ReadonlyArray<readonly [string, string]> = [
|
|
1119
1132
|
['session_start', 'sessionStart'],
|
|
1120
1133
|
['session_end', 'sessionEnd'],
|
|
@@ -2472,7 +2485,7 @@ function _file_entry(p: string, kind: string, hash_content: boolean): Record<str
|
|
|
2472
2485
|
};
|
|
2473
2486
|
}
|
|
2474
2487
|
|
|
2475
|
-
type DeployResult =
|
|
2488
|
+
type DeployResult = scoped_projection.DeployTuple;
|
|
2476
2489
|
|
|
2477
2490
|
function _files_by_tool_from_deploy(
|
|
2478
2491
|
deploy_results: Record<string, DeployResult>,
|
|
@@ -3397,91 +3410,10 @@ function _verify_deploy_targets(anchor: string, plan: ReadonlyArray<readonly [st
|
|
|
3397
3410
|
return missing;
|
|
3398
3411
|
}
|
|
3399
3412
|
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
* road-to-credible-install Phase 2 to back both the core-only lab prune and
|
|
3405
|
-
* the scoped-projection pack prune off the same mechanics). Skills are
|
|
3406
|
-
* pruned by whole directory (tier decided by the skill's `SKILL.md`
|
|
3407
|
-
* frontmatter); commands by file (own frontmatter). Rules / personas /
|
|
3408
|
-
* contexts / templates are core/shared and left intact. Returns
|
|
3409
|
-
* `[pruned_count, adjusted_results]` with the pruned paths removed from each
|
|
3410
|
-
* tool's `written_paths` so the manifest never records them.
|
|
3411
|
-
*/
|
|
3412
|
-
function _prune_modules_by(
|
|
3413
|
-
deploy_results: Record<string, DeployResult>,
|
|
3414
|
-
is_pruned: (md_path: string) => boolean,
|
|
3415
|
-
): [number, Record<string, DeployResult>] {
|
|
3416
|
-
let pruned = 0;
|
|
3417
|
-
const adjusted: Record<string, DeployResult> = {};
|
|
3418
|
-
for (const tool_id of Object.keys(deploy_results)) {
|
|
3419
|
-
const [written, skipped, status, paths] = deploy_results[tool_id] as DeployResult;
|
|
3420
|
-
const pruned_skill_dirs = new Set<string>();
|
|
3421
|
-
for (const p of paths) {
|
|
3422
|
-
const parts = p.split(path.sep);
|
|
3423
|
-
if (parts.includes('skills')) {
|
|
3424
|
-
const i = parts.indexOf('skills');
|
|
3425
|
-
if (i + 1 < parts.length) {
|
|
3426
|
-
const skill_root = parts.slice(0, i + 2).join(path.sep);
|
|
3427
|
-
if (!pruned_skill_dirs.has(skill_root)) {
|
|
3428
|
-
const skillmd = path.join(skill_root, 'SKILL.md');
|
|
3429
|
-
if (pathExists(skillmd) && is_pruned(skillmd)) {
|
|
3430
|
-
pruned_skill_dirs.add(skill_root);
|
|
3431
|
-
}
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
}
|
|
3436
|
-
const keep: string[] = [];
|
|
3437
|
-
const delete_files: string[] = [];
|
|
3438
|
-
for (const p of paths) {
|
|
3439
|
-
const parts = p.split(path.sep);
|
|
3440
|
-
let is_target = false;
|
|
3441
|
-
if (parts.includes('skills')) {
|
|
3442
|
-
const i = parts.indexOf('skills');
|
|
3443
|
-
if (i + 1 < parts.length && pruned_skill_dirs.has(parts.slice(0, i + 2).join(path.sep))) {
|
|
3444
|
-
is_target = true;
|
|
3445
|
-
}
|
|
3446
|
-
} else if (
|
|
3447
|
-
parts.includes('commands') &&
|
|
3448
|
-
path.extname(p) === '.md' &&
|
|
3449
|
-
is_pruned(p)
|
|
3450
|
-
) {
|
|
3451
|
-
is_target = true;
|
|
3452
|
-
}
|
|
3453
|
-
(is_target ? delete_files : keep).push(p);
|
|
3454
|
-
}
|
|
3455
|
-
for (const d of pruned_skill_dirs) {
|
|
3456
|
-
fs.rmSync(d, { recursive: true, force: true });
|
|
3457
|
-
}
|
|
3458
|
-
for (const p of delete_files) {
|
|
3459
|
-
if (p.split(path.sep).includes('commands') && pathExists(p)) {
|
|
3460
|
-
try {
|
|
3461
|
-
fs.unlinkSync(p);
|
|
3462
|
-
} catch {
|
|
3463
|
-
// OSError → swallow, mirroring the .py.
|
|
3464
|
-
}
|
|
3465
|
-
}
|
|
3466
|
-
}
|
|
3467
|
-
pruned += delete_files.length;
|
|
3468
|
-
adjusted[tool_id] = [Math.max(0, written - delete_files.length), skipped, status, keep];
|
|
3469
|
-
}
|
|
3470
|
-
return [pruned, adjusted];
|
|
3471
|
-
}
|
|
3472
|
-
|
|
3473
|
-
/**
|
|
3474
|
-
* Remove lab-tier skills/commands from a completed deploy (core-only).
|
|
3475
|
-
*
|
|
3476
|
-
* road-to-install-contract-stability Phase 2 Step 2. Thin wrapper over
|
|
3477
|
-
* `_prune_modules_by` — see that function for the mechanics.
|
|
3478
|
-
*/
|
|
3479
|
-
function _prune_lab_modules(
|
|
3480
|
-
deploy_results: Record<string, DeployResult>,
|
|
3481
|
-
lab_ids: Set<string>,
|
|
3482
|
-
): [number, Record<string, DeployResult>] {
|
|
3483
|
-
return _prune_modules_by(deploy_results, (p) => surface_tiers.is_lab_artefact(p, lab_ids));
|
|
3484
|
-
}
|
|
3413
|
+
// The prune mechanics moved WHOLE into `_lib/scoped_projection.ts` beside the
|
|
3414
|
+
// predicate they consume — a pure move, names forwarded, no behaviour change.
|
|
3415
|
+
const _prune_modules_by = scoped_projection.prune_modules_by;
|
|
3416
|
+
const _prune_lab_modules = scoped_projection.prune_lab_modules;
|
|
3485
3417
|
|
|
3486
3418
|
// --- Scoped-projection prune (road-to-credible-install Phase 2) ----------
|
|
3487
3419
|
//
|
|
@@ -3549,10 +3481,10 @@ function _resolve_global_settings_path(): string | null {
|
|
|
3549
3481
|
*/
|
|
3550
3482
|
function _resolve_scoped_projection(
|
|
3551
3483
|
package_root: string,
|
|
3552
|
-
): { mode:
|
|
3484
|
+
): { mode: mcp_bridge.ProjectionMode; active_packs: string[] } {
|
|
3553
3485
|
const doc = _resolve_global_settings_doc() ?? _load_default_settings(package_root);
|
|
3554
3486
|
const projection = _isPlainObject(doc['projection']) ? (doc['projection'] as Record<string, unknown>) : {};
|
|
3555
|
-
const mode
|
|
3487
|
+
const mode = mcp_bridge.projectionModeOf(projection['mode']);
|
|
3556
3488
|
const runtime = _isPlainObject(doc['runtime']) ? (doc['runtime'] as Record<string, unknown>) : {};
|
|
3557
3489
|
const active_packs_raw = runtime['active_packs'];
|
|
3558
3490
|
const active_packs = Array.isArray(active_packs_raw)
|
|
@@ -3782,6 +3714,13 @@ function install_global(
|
|
|
3782
3714
|
// here and restores the full tree — never a partial or crashed prune.
|
|
3783
3715
|
try {
|
|
3784
3716
|
const { mode, active_packs } = _resolve_scoped_projection(package_root);
|
|
3717
|
+
if (mode === 'tiered') {
|
|
3718
|
+
const outcome = mcp_bridge.applyTieredPrune(deploy_results, package_root, _prune_modules_by);
|
|
3719
|
+
deploy_results = outcome.deployResults;
|
|
3720
|
+
if (!state.QUIET && outcome.message !== null) {
|
|
3721
|
+
(outcome.level === 'warn' ? warn : info)(outcome.message);
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3785
3724
|
if (mode === 'scoped') {
|
|
3786
3725
|
const packs_registry = _load_packs_registry(package_root);
|
|
3787
3726
|
const active_ids = _compute_active_pack_ids(packs_registry, active_packs);
|
|
@@ -5225,7 +5164,10 @@ function _main_project_install(
|
|
|
5225
5164
|
...ensure_augment_bridge(project_root, opts.force),
|
|
5226
5165
|
];
|
|
5227
5166
|
if (_is_tool_enabled(tools, 'claude-code')) {
|
|
5228
|
-
merged_keys_by_tool['claude-code'] =
|
|
5167
|
+
merged_keys_by_tool['claude-code'] = [
|
|
5168
|
+
...ensure_claude_bridge(project_root, opts.force),
|
|
5169
|
+
...ensure_mcp_bridge(project_root, opts.force),
|
|
5170
|
+
];
|
|
5229
5171
|
}
|
|
5230
5172
|
if (_is_tool_enabled(tools, 'cursor')) {
|
|
5231
5173
|
merged_keys_by_tool['cursor'] = ensure_cursor_bridge(project_root, opts.force);
|
|
@@ -5249,6 +5191,11 @@ function _main_project_install(
|
|
|
5249
5191
|
if (_is_tool_enabled(tools, 'kiro')) ensure_kiro_bridge(project_root, opts.force);
|
|
5250
5192
|
}
|
|
5251
5193
|
|
|
5194
|
+
const tier_advisory = _tier_b_advisory(package_root);
|
|
5195
|
+
if (tier_advisory !== null && !state.QUIET) {
|
|
5196
|
+
info(tier_advisory);
|
|
5197
|
+
}
|
|
5198
|
+
|
|
5252
5199
|
if (opts.augment_user_hooks) {
|
|
5253
5200
|
(merged_keys_by_tool['augment'] ??= []).push(...ensure_augment_user_hooks(package_root, opts.force));
|
|
5254
5201
|
}
|
|
@@ -5441,6 +5388,10 @@ export {
|
|
|
5441
5388
|
GEMINI_DISPATCHER_BINDINGS,
|
|
5442
5389
|
ensure_cursor_bridge,
|
|
5443
5390
|
ensure_cline_bridge,
|
|
5391
|
+
ensure_mcp_bridge,
|
|
5392
|
+
_prune_tier_b_modules,
|
|
5393
|
+
_resolve_tier_b,
|
|
5394
|
+
_tier_b_advisory,
|
|
5444
5395
|
ensure_windsurf_bridge,
|
|
5445
5396
|
ensure_gemini_bridge,
|
|
5446
5397
|
// road-to-credible-install Phase 2: exported for the scoped-projection
|