@event4u/agent-config 14.9.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 +384 -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/async-python-patterns/SKILL.md +1 -1
- 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-refactoring/SKILL.md +1 -1
- 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 +4 -1
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +4 -1
- 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 +80 -2
- 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/discovery-interview/SKILL.md +1 -1
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
- package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/editorial-calendar/SKILL.md +1 -1
- 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/github-ci/SKILL.md +1 -1
- 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/judge-artifact-completeness/SKILL.md +1 -1
- package/dist/agent-src/skills/judge-injection-defense/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
- package/dist/agent-src/skills/laravel-validation/SKILL.md +1 -1
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
- package/dist/agent-src/skills/legal-intake-triage/SKILL.md +1 -1
- package/dist/agent-src/skills/legal-practice-profile/SKILL.md +1 -1
- 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/messaging-architecture/SKILL.md +1 -1
- package/dist/agent-src/skills/migration-architect/SKILL.md +1 -1
- package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -1
- package/dist/agent-src/skills/module-management/SKILL.md +1 -1
- 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 +7 -1
- package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
- package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
- 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/perf-feedback-craft/SKILL.md +1 -1
- 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/prompt-optimizer/SKILL.md +1 -1
- 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 +3 -3
- 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/SKILL.md +1 -1
- package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
- package/dist/agent-src/skills/secrets-management/SKILL.md +5 -1
- 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/using-git-worktrees/SKILL.md +1 -1
- 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 +380 -145
- 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 +227 -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/preamble-payload-budget.json +71 -67
- 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/seating.ts +211 -0
- 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_pack_passport_reconciliation.ts +274 -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/generate_pack_manifests.ts +78 -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/pack.schema.json +62 -4
- package/src/scripts/schemas/rule.schema.json +24 -2
- package/src/scripts/schemas/skill.schema.json +41 -2
- 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/tighten_skill_descriptions.ts +264 -0
- 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
|
@@ -57,6 +57,21 @@ export interface RunCheckpoint {
|
|
|
57
57
|
readonly next_step: string | null;
|
|
58
58
|
/** Commit the tree was on. A resume onto a different commit is normal, and visible. */
|
|
59
59
|
readonly head: string | null;
|
|
60
|
+
/**
|
|
61
|
+
* The situational-awareness reading this run last took —
|
|
62
|
+
* `contextFingerprint()` over `origin/main` plus every open PR's head SHA.
|
|
63
|
+
*
|
|
64
|
+
* `road-to-roadmap-situational-awareness` § 5.6. Every other field here
|
|
65
|
+
* reports **roadmap** drift; none reported **repository** drift, so a run
|
|
66
|
+
* resumed after a long gap trusted a context reading it never re-took. A
|
|
67
|
+
* disagreement here forces a re-probe before the first step.
|
|
68
|
+
*
|
|
69
|
+
* Optional: a checkpoint written before this field existed, or by a run that
|
|
70
|
+
* could not reach the probe, is still a valid checkpoint. Absent means "not
|
|
71
|
+
* known", never "unchanged" — `verifyCheckpoint` treats a null on either
|
|
72
|
+
* side as unknown, the same way it already treats `head`.
|
|
73
|
+
*/
|
|
74
|
+
readonly context_fingerprint?: string | null;
|
|
60
75
|
readonly written_at: string;
|
|
61
76
|
}
|
|
62
77
|
|
|
@@ -109,6 +124,16 @@ export interface BuildOptions {
|
|
|
109
124
|
/** Injected so a test does not depend on the ambient git state. */
|
|
110
125
|
readonly head?: string | null;
|
|
111
126
|
readonly now?: () => Date;
|
|
127
|
+
/**
|
|
128
|
+
* The run's situational-awareness fingerprint
|
|
129
|
+
* (`roadmap:context --fingerprint`). Injected rather than read here, so this
|
|
130
|
+
* library keeps its no-subprocess property — `readHead` reads `.git`
|
|
131
|
+
* directly for the same reason, and the probe cannot.
|
|
132
|
+
*
|
|
133
|
+
* Omitted → the field is absent, and a resume reports "not known" rather
|
|
134
|
+
* than asserting the repository stood still.
|
|
135
|
+
*/
|
|
136
|
+
readonly contextFingerprint?: string | null;
|
|
112
137
|
}
|
|
113
138
|
|
|
114
139
|
/**
|
|
@@ -204,6 +229,12 @@ export function buildCheckpoint(
|
|
|
204
229
|
parked_steps: counts.parked,
|
|
205
230
|
next_step: counts.next,
|
|
206
231
|
head: opts.head ?? readHead(repoRoot),
|
|
232
|
+
// Absent rather than null when nothing was supplied: a checkpoint that
|
|
233
|
+
// predates this field and one written without a probe are the same
|
|
234
|
+
// state, and both must read as "not known".
|
|
235
|
+
...(opts.contextFingerprint !== undefined
|
|
236
|
+
? { context_fingerprint: opts.contextFingerprint }
|
|
237
|
+
: {}),
|
|
207
238
|
written_at: (opts.now ?? ((): Date => new Date()))().toISOString(),
|
|
208
239
|
};
|
|
209
240
|
}
|
|
@@ -310,7 +341,16 @@ export interface VerifyResult {
|
|
|
310
341
|
* 4, actual 3" tells it a step landed after the checkpoint was written and
|
|
311
342
|
* which count to trust.
|
|
312
343
|
*/
|
|
313
|
-
export function verifyCheckpoint(
|
|
344
|
+
export function verifyCheckpoint(
|
|
345
|
+
repoRoot: string,
|
|
346
|
+
cp: RunCheckpoint,
|
|
347
|
+
/**
|
|
348
|
+
* The fingerprint a fresh `roadmap:context --fingerprint` returned, when the
|
|
349
|
+
* resumed run took one. Omitted → the field reports "not known" rather than
|
|
350
|
+
* asserting the repository stood still.
|
|
351
|
+
*/
|
|
352
|
+
currentFingerprint?: string | null,
|
|
353
|
+
): VerifyResult {
|
|
314
354
|
let text: string;
|
|
315
355
|
try {
|
|
316
356
|
text = fs.readFileSync(roadmapPath(repoRoot, cp.roadmap), 'utf-8');
|
|
@@ -349,6 +389,19 @@ export function verifyCheckpoint(repoRoot: string, cp: RunCheckpoint): VerifyRes
|
|
|
349
389
|
// than a missing one: it trains the reader to skip the line.
|
|
350
390
|
agrees: cp.head === null || head === null || cp.head === head,
|
|
351
391
|
},
|
|
392
|
+
// Repository drift, which no other field here reports. The `actual` is
|
|
393
|
+
// supplied by the caller (the probe is a subprocess and this library
|
|
394
|
+
// stays I/O-light) — absent means the caller did not re-probe, and an
|
|
395
|
+
// unknown on either side is never a disagreement, exactly as for `head`.
|
|
396
|
+
{
|
|
397
|
+
field: 'context_fingerprint',
|
|
398
|
+
claimed: cp.context_fingerprint ?? null,
|
|
399
|
+
actual: currentFingerprint ?? null,
|
|
400
|
+
agrees:
|
|
401
|
+
(cp.context_fingerprint ?? null) === null ||
|
|
402
|
+
(currentFingerprint ?? null) === null ||
|
|
403
|
+
cp.context_fingerprint === currentFingerprint,
|
|
404
|
+
},
|
|
352
405
|
];
|
|
353
406
|
return { readable: true, fields, agrees: fields.every((f) => f.agrees) };
|
|
354
407
|
}
|
|
@@ -260,3 +260,99 @@ export function scoped_projection_stats(
|
|
|
260
260
|
workspaces: [...SCOPED_ACTIVE_WORKSPACES].sort(),
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
|
+
|
|
264
|
+
/** The installer's deploy tuple: [written, skipped, status, paths]. */
|
|
265
|
+
export type DeployTuple = [number, number, string, string[]];
|
|
266
|
+
|
|
267
|
+
// --- Deploy-tree prune mechanics ------------------------------------------
|
|
268
|
+
// Moved here WHOLE from `install.ts` (a pure move, names forwarded there) so
|
|
269
|
+
// the prune sits beside `is_pruned_under_scoped`, the predicate it consumes —
|
|
270
|
+
// which is what this module's header says it exists for. It also pays for the
|
|
271
|
+
// `check_source_size_budget` ratchet, which counts every line in a file above
|
|
272
|
+
// 1,500 and which `install.ts` at 5,466 lines cannot grow past.
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Remove skills/commands matching `is_pruned` from a completed deploy.
|
|
276
|
+
*
|
|
277
|
+
* road-to-install-contract-stability Phase 2 Step 2 (generalized in
|
|
278
|
+
* road-to-credible-install Phase 2 to back both the core-only lab prune and
|
|
279
|
+
* the scoped-projection pack prune off the same mechanics). Skills are
|
|
280
|
+
* pruned by whole directory (tier decided by the skill's `SKILL.md`
|
|
281
|
+
* frontmatter); commands by file (own frontmatter). Rules / personas /
|
|
282
|
+
* contexts / templates are core/shared and left intact. Returns
|
|
283
|
+
* `[pruned_count, adjusted_results]` with the pruned paths removed from each
|
|
284
|
+
* tool's `written_paths` so the manifest never records them.
|
|
285
|
+
*/
|
|
286
|
+
export function prune_modules_by(
|
|
287
|
+
deploy_results: Record<string, DeployTuple>,
|
|
288
|
+
is_pruned: (md_path: string) => boolean,
|
|
289
|
+
): [number, Record<string, DeployTuple>] {
|
|
290
|
+
let pruned = 0;
|
|
291
|
+
const adjusted: Record<string, DeployTuple> = {};
|
|
292
|
+
for (const tool_id of Object.keys(deploy_results)) {
|
|
293
|
+
const [written, skipped, status, paths] = deploy_results[tool_id] as DeployTuple;
|
|
294
|
+
const pruned_skill_dirs = new Set<string>();
|
|
295
|
+
for (const p of paths) {
|
|
296
|
+
const parts = p.split(path.sep);
|
|
297
|
+
if (parts.includes('skills')) {
|
|
298
|
+
const i = parts.indexOf('skills');
|
|
299
|
+
if (i + 1 < parts.length) {
|
|
300
|
+
const skill_root = parts.slice(0, i + 2).join(path.sep);
|
|
301
|
+
if (!pruned_skill_dirs.has(skill_root)) {
|
|
302
|
+
const skillmd = path.join(skill_root, 'SKILL.md');
|
|
303
|
+
if (fs.existsSync(skillmd) && is_pruned(skillmd)) {
|
|
304
|
+
pruned_skill_dirs.add(skill_root);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const keep: string[] = [];
|
|
311
|
+
const delete_files: string[] = [];
|
|
312
|
+
for (const p of paths) {
|
|
313
|
+
const parts = p.split(path.sep);
|
|
314
|
+
let is_target = false;
|
|
315
|
+
if (parts.includes('skills')) {
|
|
316
|
+
const i = parts.indexOf('skills');
|
|
317
|
+
if (i + 1 < parts.length && pruned_skill_dirs.has(parts.slice(0, i + 2).join(path.sep))) {
|
|
318
|
+
is_target = true;
|
|
319
|
+
}
|
|
320
|
+
} else if (
|
|
321
|
+
parts.includes('commands') &&
|
|
322
|
+
path.extname(p) === '.md' &&
|
|
323
|
+
is_pruned(p)
|
|
324
|
+
) {
|
|
325
|
+
is_target = true;
|
|
326
|
+
}
|
|
327
|
+
(is_target ? delete_files : keep).push(p);
|
|
328
|
+
}
|
|
329
|
+
for (const d of pruned_skill_dirs) {
|
|
330
|
+
fs.rmSync(d, { recursive: true, force: true });
|
|
331
|
+
}
|
|
332
|
+
for (const p of delete_files) {
|
|
333
|
+
if (p.split(path.sep).includes('commands') && fs.existsSync(p)) {
|
|
334
|
+
try {
|
|
335
|
+
fs.unlinkSync(p);
|
|
336
|
+
} catch {
|
|
337
|
+
// OSError → swallow, mirroring the .py.
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
pruned += delete_files.length;
|
|
342
|
+
adjusted[tool_id] = [Math.max(0, written - delete_files.length), skipped, status, keep];
|
|
343
|
+
}
|
|
344
|
+
return [pruned, adjusted];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Remove lab-tier skills/commands from a completed deploy (core-only).
|
|
349
|
+
*
|
|
350
|
+
* road-to-install-contract-stability Phase 2 Step 2. Thin wrapper over
|
|
351
|
+
* `_prune_modules_by` — see that function for the mechanics.
|
|
352
|
+
*/
|
|
353
|
+
export function prune_lab_modules(
|
|
354
|
+
deploy_results: Record<string, DeployTuple>,
|
|
355
|
+
lab_ids: Set<string>,
|
|
356
|
+
): [number, Record<string, DeployTuple>] {
|
|
357
|
+
return prune_modules_by(deploy_results, (p) => surface_tiers.is_lab_artefact(p, lab_ids));
|
|
358
|
+
}
|
|
@@ -226,6 +226,22 @@ export interface SessionRecord {
|
|
|
226
226
|
* session that was never refused, is still a valid record.
|
|
227
227
|
*/
|
|
228
228
|
turn_end_refusals?: Record<string, number>;
|
|
229
|
+
/**
|
|
230
|
+
* Repo-relative paths this session has declared it owns, or absent when it
|
|
231
|
+
* has declared none.
|
|
232
|
+
*
|
|
233
|
+
* `road-to-roadmap-situational-awareness` § 3.1. The register compared slugs
|
|
234
|
+
* and branch names and nothing else, so two sessions on two different
|
|
235
|
+
* roadmaps that happen to edit the same file were invisible to each other —
|
|
236
|
+
* the axis that actually predicts a merge conflict was the one axis nobody
|
|
237
|
+
* carried.
|
|
238
|
+
*
|
|
239
|
+
* Additive on exactly the terms `turn_end_refusals` established: a session
|
|
240
|
+
* that declared no paths leaves the record **byte-identical** to what it was
|
|
241
|
+
* before this field existed, so a reader that does not know the field is
|
|
242
|
+
* unaffected and a diff of two records still shows only what changed.
|
|
243
|
+
*/
|
|
244
|
+
owned_paths?: string[];
|
|
229
245
|
}
|
|
230
246
|
|
|
231
247
|
/**
|
|
@@ -430,11 +446,21 @@ export function foreign_live_records(
|
|
|
430
446
|
* so the branch comparison was silent by construction while a whole
|
|
431
447
|
* implementation was duplicated. One of the two PRs is thrown away either way.
|
|
432
448
|
*/
|
|
433
|
-
|
|
449
|
+
/**
|
|
450
|
+
* `path` is the third axis, added last and cheapest to be wrong about: two
|
|
451
|
+
* sessions can be on different roadmaps and different branches and still be
|
|
452
|
+
* editing one file. It is reported SEPARATELY rather than folded into either of
|
|
453
|
+
* the two above, because the response differs — a roadmap collision means stop,
|
|
454
|
+
* a branch collision means coordinate, a path collision means take the disjoint
|
|
455
|
+
* steps first and say so.
|
|
456
|
+
*/
|
|
457
|
+
export type CollisionKind = 'roadmap' | 'branch' | 'path';
|
|
434
458
|
|
|
435
459
|
export interface Collision {
|
|
436
460
|
kind: CollisionKind;
|
|
437
461
|
record: SessionRecord;
|
|
462
|
+
/** For `kind: 'path'`, the shared paths. Absent on the other two kinds. */
|
|
463
|
+
paths?: string[];
|
|
438
464
|
}
|
|
439
465
|
|
|
440
466
|
/**
|
|
@@ -451,7 +477,11 @@ export interface Collision {
|
|
|
451
477
|
*/
|
|
452
478
|
export function classify_collisions(
|
|
453
479
|
others: readonly SessionRecord[],
|
|
454
|
-
here: {
|
|
480
|
+
here: {
|
|
481
|
+
branch: string | null;
|
|
482
|
+
roadmap_slug: string | null;
|
|
483
|
+
owned_paths?: readonly string[];
|
|
484
|
+
},
|
|
455
485
|
): Collision[] {
|
|
456
486
|
const out: Collision[] = [];
|
|
457
487
|
for (const r of others) {
|
|
@@ -468,5 +498,17 @@ export function classify_collisions(
|
|
|
468
498
|
out.push({ kind: 'branch', record: r });
|
|
469
499
|
}
|
|
470
500
|
}
|
|
501
|
+
// Last, and last on purpose: the two axes above are unchanged in meaning and
|
|
502
|
+
// in order, so a consumer that filters on `roadmap` or `branch` sees exactly
|
|
503
|
+
// what it saw before this axis existed.
|
|
504
|
+
const mine = new Set(here.owned_paths ?? []);
|
|
505
|
+
if (mine.size > 0) {
|
|
506
|
+
for (const r of others) {
|
|
507
|
+
const shared = (r.owned_paths ?? []).filter((p) => mine.has(p)).sort();
|
|
508
|
+
if (shared.length > 0) {
|
|
509
|
+
out.push({ kind: 'path', record: r, paths: shared });
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
471
513
|
return out;
|
|
472
514
|
}
|
|
@@ -730,6 +730,17 @@ export interface ProjectionModeCounts {
|
|
|
730
730
|
prunedUnderScoped: number;
|
|
731
731
|
/** Pack ids active by default under `scoped`, sorted. */
|
|
732
732
|
activePacks: string[];
|
|
733
|
+
/**
|
|
734
|
+
* Skills a `projection.mode: tiered` install deploys natively — those
|
|
735
|
+
* predicted to reach the model WITH their description. `null` when no tier
|
|
736
|
+
* split exists on this machine, which is the common case and is NOT zero.
|
|
737
|
+
*/
|
|
738
|
+
tierACount: number | null;
|
|
739
|
+
/**
|
|
740
|
+
* Skills `tiered` withholds from the native catalogue; still served by the
|
|
741
|
+
* MCP recovery tools. `null` under the same condition as `tierACount`.
|
|
742
|
+
*/
|
|
743
|
+
tierBCount: number | null;
|
|
733
744
|
}
|
|
734
745
|
|
|
735
746
|
/**
|
|
@@ -791,8 +802,26 @@ export function formatProjectionModes(
|
|
|
791
802
|
` legacy-all: ${counts.legacyAll}`,
|
|
792
803
|
` pruned under scoped: ${counts.prunedUnderScoped}`,
|
|
793
804
|
` active packs under scoped: ${counts.activePacks.length}`,
|
|
794
|
-
'',
|
|
795
805
|
];
|
|
806
|
+
if (counts.tierACount === null || counts.tierBCount === null) {
|
|
807
|
+
lines.push(
|
|
808
|
+
' tiered: no split on this machine (agents/runtime/state/skill-tiers.json',
|
|
809
|
+
' absent) — not zero, unmeasured. `tiered` ships the full surface',
|
|
810
|
+
' until a split exists.',
|
|
811
|
+
);
|
|
812
|
+
} else {
|
|
813
|
+
lines.push(
|
|
814
|
+
` tiered: tier A ${counts.tierACount} native + tier B ${counts.tierBCount} ` +
|
|
815
|
+
`MCP-only = ${counts.tierACount + counts.tierBCount}`,
|
|
816
|
+
);
|
|
817
|
+
if (counts.tierACount + counts.tierBCount !== counts.legacyAll) {
|
|
818
|
+
lines.push(
|
|
819
|
+
` ⚠️ tier A + tier B (${counts.tierACount + counts.tierBCount}) != ` +
|
|
820
|
+
`legacy-all (${counts.legacyAll}) — the split is STALE, recompute it.`,
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
lines.push('');
|
|
796
825
|
if (rows.length === 0) {
|
|
797
826
|
lines.push(
|
|
798
827
|
'No host root measured. Pass --host-root <dir> (repeatable) to read what',
|
|
@@ -959,6 +988,7 @@ export interface MigrationEligibility {
|
|
|
959
988
|
| 'observation-not-comparable'
|
|
960
989
|
| 'no-truncation-observed'
|
|
961
990
|
| 'already-scoped'
|
|
991
|
+
| 'already-tiered'
|
|
962
992
|
| 'below-observed-skill-volume';
|
|
963
993
|
/** Populated only when eligible, for the message. */
|
|
964
994
|
droppedEntries?: number;
|
|
@@ -981,11 +1011,17 @@ export interface MigrationEligibility {
|
|
|
981
1011
|
*/
|
|
982
1012
|
export function migrationEligibility(
|
|
983
1013
|
host: string,
|
|
984
|
-
resolvedMode: 'scoped' | 'legacy-all',
|
|
1014
|
+
resolvedMode: 'scoped' | 'legacy-all' | 'tiered',
|
|
985
1015
|
currentSkillCount: number,
|
|
986
1016
|
limits: ReadonlyMap<string, KnownHostLimit>,
|
|
987
1017
|
): MigrationEligibility {
|
|
988
1018
|
if (resolvedMode === 'scoped') return { eligible: false, reason: 'already-scoped' };
|
|
1019
|
+
// `tiered` already withholds skills from the native catalogue, so an offer to
|
|
1020
|
+
// migrate to `scoped` has nothing to buy. It gets its OWN reason rather than
|
|
1021
|
+
// reusing `already-scoped`: the two narrow on different axes (packs vs the
|
|
1022
|
+
// host's listing budget), and a caller reading the reason should be able to
|
|
1023
|
+
// tell which one the install is actually on.
|
|
1024
|
+
if (resolvedMode === 'tiered') return { eligible: false, reason: 'already-tiered' };
|
|
989
1025
|
const limit = limits.get(host);
|
|
990
1026
|
if (limit === undefined) return { eligible: false, reason: 'no-observation-for-host' };
|
|
991
1027
|
if (limit.projectedSkills === null) return { eligible: false, reason: 'observation-not-comparable' };
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-read measurement over Claude Code transcript legs.
|
|
3
|
+
*
|
|
4
|
+
* `road-to-role-scoped-spawn-profiles` Phase 3 Step 3 requires a re-read
|
|
5
|
+
* measurement BEFORE any suppression: *"A suppression built without this
|
|
6
|
+
* measurement is suppressing whatever the author happened to notice."* This
|
|
7
|
+
* module is that measurement, and it is deliberately a sibling of
|
|
8
|
+
* `cc_transcript.ts` rather than a widening of it — `scanTranscripts` keeps
|
|
9
|
+
* only `type: "assistant"` records carrying a `usage` block, which is exactly
|
|
10
|
+
* the population a `tool_result` is NOT in.
|
|
11
|
+
*
|
|
12
|
+
* **What a "leg" is, stated because every count below depends on it.** One
|
|
13
|
+
* `.jsonl` file is one leg. Claude Code writes the main session to
|
|
14
|
+
* `<project>/<sessionId>.jsonl` and each subagent to
|
|
15
|
+
* `<project>/<sessionId>/subagents/agent-*.jsonl`, so a leg is a single
|
|
16
|
+
* conversation whose context window is its own. A file read once in the main
|
|
17
|
+
* leg and once inside a subagent is NOT a re-read — the second leg never had
|
|
18
|
+
* the first one's context — and {@link computeRereads} counts per leg for that
|
|
19
|
+
* reason.
|
|
20
|
+
*
|
|
21
|
+
* **The wasted-token figure is a `chars / 4` PROXY, not a measurement.** The
|
|
22
|
+
* transcript records no per-tool-result token count, so the size of a
|
|
23
|
+
* duplicate read is estimated from the JSON-encoded length of its
|
|
24
|
+
* `tool_result` body. Every caller must label it as a proxy; this module names
|
|
25
|
+
* the field `wasted_tokens_proxy` so the label cannot be dropped by accident.
|
|
26
|
+
*
|
|
27
|
+
* Read-only: no writes, no network, no spawn.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import * as fs from 'node:fs';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Tools whose result is a file body the model already holds after the first
|
|
34
|
+
* call. Deliberately narrow: `Edit` and `Write` also carry a `file_path`, but
|
|
35
|
+
* re-reading after a mutation is correct behaviour, not waste, so counting
|
|
36
|
+
* them would manufacture "re-reads" out of the loop this measurement exists to
|
|
37
|
+
* distinguish from.
|
|
38
|
+
*/
|
|
39
|
+
export const READ_SHAPED_TOOLS: ReadonlySet<string> = new Set(['Read', 'NotebookRead']);
|
|
40
|
+
|
|
41
|
+
/** One observed read-shaped tool call inside one leg. */
|
|
42
|
+
export interface ReadEvent {
|
|
43
|
+
filePath: string;
|
|
44
|
+
/** JSON-encoded length of the matching `tool_result` body; 0 when no result was recorded. */
|
|
45
|
+
resultChars: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Per-path rollup across every leg that read it more than once. */
|
|
49
|
+
export interface RereadFile {
|
|
50
|
+
file_path: string;
|
|
51
|
+
/** Total read-shaped calls on this path, across all legs. */
|
|
52
|
+
total_reads: number;
|
|
53
|
+
/** Reads beyond the first WITHIN a leg, summed over legs. */
|
|
54
|
+
duplicate_reads: number;
|
|
55
|
+
/** Number of legs in which this path was read at least twice. */
|
|
56
|
+
legs_with_reread: number;
|
|
57
|
+
/** `chars / 4` proxy over the duplicate reads only — never a measurement. */
|
|
58
|
+
wasted_tokens_proxy: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface RereadResult {
|
|
62
|
+
legs_scanned: number;
|
|
63
|
+
total_reads: number;
|
|
64
|
+
duplicate_reads: number;
|
|
65
|
+
wasted_tokens_proxy: number;
|
|
66
|
+
/** Only paths with at least one duplicate, ranked by `wasted_tokens_proxy` desc. */
|
|
67
|
+
files: RereadFile[];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseLine(line: string): Record<string, unknown> | null {
|
|
71
|
+
const t = line.trim();
|
|
72
|
+
if (t.length === 0) return null;
|
|
73
|
+
try {
|
|
74
|
+
const v = JSON.parse(t) as unknown;
|
|
75
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? (v as Record<string, unknown>) : null;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function contentBlocks(rec: Record<string, unknown>): Array<Record<string, unknown>> {
|
|
82
|
+
const msg = rec.message;
|
|
83
|
+
if (!msg || typeof msg !== 'object' || Array.isArray(msg)) return [];
|
|
84
|
+
const content = (msg as Record<string, unknown>).content;
|
|
85
|
+
if (!Array.isArray(content)) return [];
|
|
86
|
+
return content.filter((c): c is Record<string, unknown> => !!c && typeof c === 'object' && !Array.isArray(c));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function readPathOf(input: unknown): string | null {
|
|
90
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) return null;
|
|
91
|
+
const o = input as Record<string, unknown>;
|
|
92
|
+
for (const key of ['file_path', 'filePath', 'notebook_path', 'notebookPath']) {
|
|
93
|
+
const v = o[key];
|
|
94
|
+
if (typeof v === 'string' && v.length > 0) return v;
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Every read-shaped call in one leg, in call order, each paired with the size
|
|
101
|
+
* of its result.
|
|
102
|
+
*
|
|
103
|
+
* Two passes on purpose: a `tool_result` can only be matched by
|
|
104
|
+
* `tool_use_id`, and nothing guarantees it appears after its `tool_use` in
|
|
105
|
+
* file order once a transcript has been resumed or replayed. An unreadable or
|
|
106
|
+
* malformed file yields `[]` — this is instrumentation, and a measurement that
|
|
107
|
+
* throws on one bad leg reports nothing about the other two thousand.
|
|
108
|
+
*/
|
|
109
|
+
export function collectReadEvents(file: string): ReadEvent[] {
|
|
110
|
+
let text: string;
|
|
111
|
+
try {
|
|
112
|
+
text = fs.readFileSync(file, 'utf-8');
|
|
113
|
+
} catch {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const order: Array<{ id: string | null; filePath: string }> = [];
|
|
118
|
+
const sizes = new Map<string, number>();
|
|
119
|
+
|
|
120
|
+
for (const line of text.split('\n')) {
|
|
121
|
+
const rec = parseLine(line);
|
|
122
|
+
if (!rec) continue;
|
|
123
|
+
for (const block of contentBlocks(rec)) {
|
|
124
|
+
if (block.type === 'tool_use') {
|
|
125
|
+
if (typeof block.name !== 'string' || !READ_SHAPED_TOOLS.has(block.name)) continue;
|
|
126
|
+
const filePath = readPathOf(block.input);
|
|
127
|
+
if (filePath === null) continue;
|
|
128
|
+
order.push({ id: typeof block.id === 'string' ? block.id : null, filePath });
|
|
129
|
+
} else if (block.type === 'tool_result') {
|
|
130
|
+
const id = block.tool_use_id ?? block.toolUseId;
|
|
131
|
+
if (typeof id !== 'string') continue;
|
|
132
|
+
let chars = 0;
|
|
133
|
+
try {
|
|
134
|
+
chars = JSON.stringify(block.content ?? '').length;
|
|
135
|
+
} catch {
|
|
136
|
+
chars = 0;
|
|
137
|
+
}
|
|
138
|
+
sizes.set(id, chars);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return order.map((o) => ({
|
|
144
|
+
filePath: o.filePath,
|
|
145
|
+
resultChars: o.id === null ? 0 : (sizes.get(o.id) ?? 0),
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const CHARS_PER_TOKEN_PROXY = 4;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Roll every leg up into a per-path re-read ranking.
|
|
153
|
+
*
|
|
154
|
+
* The duplicate count is per leg: the first read of a path in a leg is the
|
|
155
|
+
* cost of knowing it, every later read in the SAME leg is the waste. Legs are
|
|
156
|
+
* never joined, so a path read once in each of two legs contributes zero
|
|
157
|
+
* duplicates — see the module doc.
|
|
158
|
+
*/
|
|
159
|
+
export function computeRereads(files: readonly string[]): RereadResult {
|
|
160
|
+
const acc = new Map<string, RereadFile>();
|
|
161
|
+
let legsScanned = 0;
|
|
162
|
+
let totalReads = 0;
|
|
163
|
+
|
|
164
|
+
for (const file of files) {
|
|
165
|
+
const events = collectReadEvents(file);
|
|
166
|
+
legsScanned += 1;
|
|
167
|
+
if (events.length === 0) continue;
|
|
168
|
+
|
|
169
|
+
const seenInLeg = new Map<string, number>();
|
|
170
|
+
for (const ev of events) {
|
|
171
|
+
totalReads += 1;
|
|
172
|
+
const priorInLeg = seenInLeg.get(ev.filePath) ?? 0;
|
|
173
|
+
seenInLeg.set(ev.filePath, priorInLeg + 1);
|
|
174
|
+
|
|
175
|
+
const row = acc.get(ev.filePath) ?? {
|
|
176
|
+
file_path: ev.filePath,
|
|
177
|
+
total_reads: 0,
|
|
178
|
+
duplicate_reads: 0,
|
|
179
|
+
legs_with_reread: 0,
|
|
180
|
+
wasted_tokens_proxy: 0,
|
|
181
|
+
};
|
|
182
|
+
row.total_reads += 1;
|
|
183
|
+
if (priorInLeg >= 1) {
|
|
184
|
+
row.duplicate_reads += 1;
|
|
185
|
+
row.wasted_tokens_proxy += Math.round(ev.resultChars / CHARS_PER_TOKEN_PROXY);
|
|
186
|
+
if (priorInLeg === 1) row.legs_with_reread += 1;
|
|
187
|
+
}
|
|
188
|
+
acc.set(ev.filePath, row);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const withDuplicates = [...acc.values()].filter((r) => r.duplicate_reads > 0);
|
|
193
|
+
withDuplicates.sort(
|
|
194
|
+
(a, b) =>
|
|
195
|
+
b.wasted_tokens_proxy - a.wasted_tokens_proxy ||
|
|
196
|
+
b.duplicate_reads - a.duplicate_reads ||
|
|
197
|
+
a.file_path.localeCompare(b.file_path),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
legs_scanned: legsScanned,
|
|
202
|
+
total_reads: totalReads,
|
|
203
|
+
duplicate_reads: withDuplicates.reduce((s, r) => s + r.duplicate_reads, 0),
|
|
204
|
+
wasted_tokens_proxy: withDuplicates.reduce((s, r) => s + r.wasted_tokens_proxy, 0),
|
|
205
|
+
files: withDuplicates,
|
|
206
|
+
};
|
|
207
|
+
}
|