@event4u/agent-config 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +39 -7
- package/AGENTS.md +8 -7
- package/CHANGELOG.md +557 -422
- package/CONTRIBUTING.md +1 -1
- package/README.md +18 -16
- package/dist/agent-src/commands/agent-handoff.md +5 -4
- package/dist/agent-src/commands/agent-status.md +3 -2
- package/dist/agent-src/commands/agents/audit.md +4 -3
- package/dist/agent-src/commands/agents/init.md +4 -1
- package/dist/agent-src/commands/agents/optimize.md +5 -4
- package/dist/agent-src/commands/agents/user/accept.md +1 -0
- package/dist/agent-src/commands/agents/user/init.md +1 -0
- package/dist/agent-src/commands/agents/user/review.md +1 -0
- package/dist/agent-src/commands/agents/user/show.md +1 -0
- package/dist/agent-src/commands/agents/user/update.md +1 -0
- package/dist/agent-src/commands/agents/user.md +1 -0
- package/dist/agent-src/commands/agents.md +1 -0
- package/dist/agent-src/commands/analytics/prune.md +3 -2
- package/dist/agent-src/commands/analytics/show.md +3 -2
- package/dist/agent-src/commands/analytics.md +3 -2
- package/dist/agent-src/commands/analyze/decision.md +108 -0
- package/dist/agent-src/commands/analyze/incident.md +120 -0
- package/dist/agent-src/commands/analyze/near-miss.md +113 -0
- package/dist/agent-src/commands/analyze/postmortem.md +130 -0
- package/dist/agent-src/commands/analyze/premortem.md +104 -0
- package/dist/agent-src/commands/analyze-reference-repo.md +1 -0
- package/dist/agent-src/commands/analyze.md +124 -0
- package/dist/agent-src/commands/brand/identity.md +27 -0
- package/dist/agent-src/commands/brand/review.md +27 -0
- package/dist/agent-src/commands/brand/strategy.md +27 -0
- package/dist/agent-src/commands/brand/tokens.md +28 -0
- package/dist/agent-src/commands/brand/voice.md +27 -0
- package/dist/agent-src/commands/brand.md +58 -0
- package/dist/agent-src/commands/bug-fix.md +1 -0
- package/dist/agent-src/commands/bug-investigate.md +1 -0
- package/dist/agent-src/commands/challenge-me/vision.md +3 -2
- package/dist/agent-src/commands/challenge-me/with-docs.md +3 -2
- package/dist/agent-src/commands/challenge-me.md +3 -2
- package/dist/agent-src/commands/chat-history/import.md +9 -9
- package/dist/agent-src/commands/chat-history.md +32 -30
- package/dist/agent-src/commands/check-current-md.md +4 -3
- package/dist/agent-src/commands/commit/in-chunks.md +1 -0
- package/dist/agent-src/commands/commit.md +1 -0
- package/dist/agent-src/commands/condense.md +3 -2
- package/dist/agent-src/commands/context/create.md +1 -0
- package/dist/agent-src/commands/context/refactor.md +1 -0
- package/dist/agent-src/commands/context.md +1 -0
- package/dist/agent-src/commands/cost-report.md +5 -4
- package/dist/agent-src/commands/council/analysis.md +3 -2
- package/dist/agent-src/commands/council/debate.md +7 -6
- package/dist/agent-src/commands/council/default.md +48 -20
- package/dist/agent-src/commands/council/design.md +3 -2
- package/dist/agent-src/commands/council/optimize.md +3 -2
- package/dist/agent-src/commands/council/pr.md +3 -2
- package/dist/agent-src/commands/council.md +4 -3
- package/dist/agent-src/commands/e2e-heal.md +1 -0
- package/dist/agent-src/commands/e2e-plan.md +1 -0
- package/dist/agent-src/commands/estimate-ticket.md +1 -0
- package/dist/agent-src/commands/feature/dev.md +1 -0
- package/dist/agent-src/commands/feature/explore.md +1 -0
- package/dist/agent-src/commands/feature/plan.md +6 -6
- package/dist/agent-src/commands/feature/refactor.md +1 -0
- package/dist/agent-src/commands/feature/roadmap.md +1 -0
- package/dist/agent-src/commands/feature.md +1 -0
- package/dist/agent-src/commands/fix/ci.md +1 -0
- package/dist/agent-src/commands/fix/portability.md +4 -3
- package/dist/agent-src/commands/fix/pr-comments.md +147 -15
- package/dist/agent-src/commands/fix/refs.md +4 -3
- package/dist/agent-src/commands/fix/seeder.md +1 -0
- package/dist/agent-src/commands/fix.md +8 -8
- package/dist/agent-src/commands/ghostwriter/delete.md +1 -0
- package/dist/agent-src/commands/ghostwriter/fetch.md +1 -0
- package/dist/agent-src/commands/ghostwriter/list.md +1 -0
- package/dist/agent-src/commands/ghostwriter/show.md +1 -0
- package/dist/agent-src/commands/ghostwriter/write.md +1 -0
- package/dist/agent-src/commands/ghostwriter.md +1 -0
- package/dist/agent-src/commands/grill-me.md +3 -2
- package/dist/agent-src/commands/image/analyse.md +1 -0
- package/dist/agent-src/commands/image/create.md +1 -0
- package/dist/agent-src/commands/image/verify.md +1 -0
- package/dist/agent-src/commands/image.md +1 -0
- package/dist/agent-src/commands/implement-ticket.md +37 -6
- package/dist/agent-src/commands/jira-ticket.md +1 -0
- package/dist/agent-src/commands/judge/on-diff.md +1 -0
- package/dist/agent-src/commands/judge/solo.md +1 -0
- package/dist/agent-src/commands/judge/steps.md +1 -0
- package/dist/agent-src/commands/judge.md +1 -0
- package/dist/agent-src/commands/knowledge/cross-repo.md +2 -1
- package/dist/agent-src/commands/knowledge/forget.md +1 -0
- package/dist/agent-src/commands/knowledge/ingest.md +1 -0
- package/dist/agent-src/commands/knowledge/list.md +1 -0
- package/dist/agent-src/commands/knowledge.md +1 -0
- package/dist/agent-src/commands/memory/add.md +9 -7
- package/dist/agent-src/commands/memory/learn-low-impact.md +3 -2
- package/dist/agent-src/commands/memory/load.md +7 -7
- package/dist/agent-src/commands/memory/mine-session.md +39 -12
- package/dist/agent-src/commands/memory/promote.md +3 -2
- package/dist/agent-src/commands/memory/propose.md +7 -6
- package/dist/agent-src/commands/memory.md +3 -2
- package/dist/agent-src/commands/mission/upgrade.md +182 -0
- package/dist/agent-src/commands/mode.md +1 -0
- package/dist/agent-src/commands/module/create.md +1 -0
- package/dist/agent-src/commands/module/explore.md +1 -0
- package/dist/agent-src/commands/module.md +1 -0
- package/dist/agent-src/commands/optimize/agents-dir.md +1 -0
- package/dist/agent-src/commands/optimize/augmentignore.md +1 -0
- package/dist/agent-src/commands/optimize/rtk.md +1 -0
- package/dist/agent-src/commands/optimize/skills.md +3 -2
- package/dist/agent-src/commands/optimize-prompt.md +1 -0
- package/dist/agent-src/commands/optimize.md +1 -0
- package/dist/agent-src/commands/orchestrate.md +2 -1
- package/dist/agent-src/commands/override/create.md +1 -0
- package/dist/agent-src/commands/override/manage.md +1 -0
- package/dist/agent-src/commands/override.md +1 -0
- package/dist/agent-src/commands/package-reset.md +1 -0
- package/dist/agent-src/commands/package-test.md +1 -0
- package/dist/agent-src/commands/post-as/ghostwriter.md +1 -0
- package/dist/agent-src/commands/post-as/me.md +1 -0
- package/dist/agent-src/commands/post-as.md +1 -0
- package/dist/agent-src/commands/pr/create/description-only.md +1 -0
- package/dist/agent-src/commands/pr/create.md +31 -4
- package/dist/agent-src/commands/prediction-pool.md +1 -0
- package/dist/agent-src/commands/prepare-for-review.md +1 -0
- package/dist/agent-src/commands/profile/activate.md +1 -0
- package/dist/agent-src/commands/profile/deactivate.md +1 -0
- package/dist/agent-src/commands/profile/show.md +1 -0
- package/dist/agent-src/commands/profile.md +1 -0
- package/dist/agent-src/commands/project-analyze.md +1 -0
- package/dist/agent-src/commands/project-health.md +1 -0
- package/dist/agent-src/commands/quality-fix.md +1 -0
- package/dist/agent-src/commands/refine-ticket.md +1 -0
- package/dist/agent-src/commands/research/deep.md +1 -0
- package/dist/agent-src/commands/research/report.md +1 -0
- package/dist/agent-src/commands/research.md +1 -0
- package/dist/agent-src/commands/review-changes.md +9 -0
- package/dist/agent-src/commands/review-routing.md +1 -0
- package/dist/agent-src/commands/roadmap/ai-council.md +1 -0
- package/dist/agent-src/commands/roadmap/create.md +1 -0
- package/dist/agent-src/commands/roadmap/materialize.md +73 -0
- package/dist/agent-src/commands/roadmap/process-full.md +1 -0
- package/dist/agent-src/commands/roadmap/process-phase.md +1 -0
- package/dist/agent-src/commands/roadmap/process-step.md +1 -0
- package/dist/agent-src/commands/roadmap.md +1 -0
- package/dist/agent-src/commands/rule-compliance-audit.md +1 -0
- package/dist/agent-src/commands/security-audit-config.md +84 -0
- package/dist/agent-src/commands/set-cost-profile.md +1 -0
- package/dist/agent-src/commands/skill/preview.md +2 -1
- package/dist/agent-src/commands/skill.md +1 -0
- package/dist/agent-src/commands/skills/discover.md +2 -1
- package/dist/agent-src/commands/skills.md +1 -0
- package/dist/agent-src/commands/sync-agent-settings.md +1 -0
- package/dist/agent-src/commands/sync-gitignore/fix.md +1 -0
- package/dist/agent-src/commands/sync-gitignore.md +1 -0
- package/dist/agent-src/commands/tests/create.md +1 -0
- package/dist/agent-src/commands/tests/execute.md +1 -0
- package/dist/agent-src/commands/tests.md +1 -0
- package/dist/agent-src/commands/threat-model.md +5 -4
- package/dist/agent-src/commands/update-form-request-messages.md +1 -0
- package/dist/agent-src/commands/upstream-contribute.md +4 -3
- package/dist/agent-src/commands/video/from-script.md +3 -2
- package/dist/agent-src/commands/video/from-song.md +4 -3
- package/dist/agent-src/commands/video/scene.md +2 -1
- package/dist/agent-src/commands/video/stitch.md +1 -0
- package/dist/agent-src/commands/video/storyboard.md +2 -1
- package/dist/agent-src/commands/video.md +4 -3
- package/dist/agent-src/commands/work.md +1 -0
- package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
- package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +2 -2
- package/dist/agent-src/contexts/communication/rules-auto/source-of-truth-mechanics.md +3 -3
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +6 -6
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +1 -1
- package/dist/agent-src/contexts/contracts/consumer-agents-md-guide.md +2 -2
- package/dist/agent-src/contexts/execution/evidence-discipline.md +153 -0
- package/dist/agent-src/contexts/execution/project-intelligence.md +264 -0
- package/dist/agent-src/contexts/execution/rdp-gate.md +75 -0
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +2 -1
- package/dist/agent-src/contexts/subagent-configuration.md +1 -0
- package/dist/agent-src/personas/advisors/contrarian.md +1 -1
- package/dist/agent-src/personas/advisors/executor.md +1 -1
- package/dist/agent-src/personas/advisors/expansionist.md +1 -1
- package/dist/agent-src/personas/advisors/first-principles.md +1 -1
- package/dist/agent-src/personas/advisors/outsider.md +1 -1
- package/dist/agent-src/personas/ai-video-technical-director.md +1 -1
- package/dist/agent-src/personas/brand-strategist.md +74 -0
- package/dist/agent-src/personas/design-director.md +74 -0
- package/dist/agent-src/rules/autonomous-execution.md +12 -0
- package/dist/agent-src/rules/brand-consistency.md +77 -0
- package/dist/agent-src/rules/brand-source-of-truth.md +57 -0
- package/dist/agent-src/rules/direct-answers.md +2 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +2 -0
- package/dist/agent-src/rules/external-reference-deep-dive.md +1 -1
- package/dist/agent-src/rules/git-history-discipline.md +48 -1
- package/dist/agent-src/rules/icon-consistency.md +53 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +67 -0
- package/dist/agent-src/rules/improve-before-implement.md +12 -0
- package/dist/agent-src/rules/lethal-trifecta-guard.md +80 -0
- package/dist/agent-src/rules/no-pr-progress-comments.md +3 -4
- package/dist/agent-src/rules/notes-first-reasoning.md +71 -0
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +58 -31
- package/dist/agent-src/rules/security-sensitive-stop.md +22 -3
- package/dist/agent-src/rules/size-enforcement.md +1 -1
- package/dist/agent-src/rules/source-confidentiality.md +97 -0
- package/dist/agent-src/rules/source-discovery-gate.md +98 -0
- package/dist/agent-src/rules/think-before-action.md +10 -1
- package/dist/agent-src/rules/ui-audit-gate.md +2 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +76 -0
- package/dist/agent-src/rules/user-interaction.md +1 -1
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +392 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +824 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +5 -5
- package/dist/agent-src/skills/adversarial-review/SKILL.md +14 -0
- package/dist/agent-src/skills/agent-security-review/SKILL.md +113 -0
- package/dist/agent-src/skills/agent-security-review/evals/triggers.json +52 -0
- package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +1 -1
- package/dist/agent-src/skills/ai-council/SKILL.md +4 -4
- package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +9 -13
- package/dist/agent-src/skills/async-python-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/blade-ui/SKILL.md +12 -5
- package/dist/agent-src/skills/blameless-post-mortem/SKILL.md +199 -0
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +12 -11
- package/dist/agent-src/skills/brand/ATTRIBUTION.md +38 -0
- package/dist/agent-src/skills/brand/SKILL.md +115 -0
- package/dist/agent-src/skills/brand/data/archetypes.csv +13 -0
- package/dist/agent-src/skills/brand/data/color-psychology.csv +14 -0
- package/dist/agent-src/skills/brand/data/logo-style-fit.csv +13 -0
- package/dist/agent-src/skills/brand/data/manifest.json +226 -0
- package/dist/agent-src/skills/brand/data/messaging-frameworks.csv +13 -0
- package/dist/agent-src/skills/brand/data/naming-patterns.csv +13 -0
- package/dist/agent-src/skills/brand/data/typography-principles.csv +13 -0
- package/dist/agent-src/skills/brand/data/voice-tone.csv +13 -0
- package/dist/agent-src/skills/brand/evals/triggers.json +17 -0
- package/dist/agent-src/skills/brand-asset-generation/SKILL.md +89 -0
- package/dist/agent-src/skills/brand-asset-generation/evals/triggers.json +17 -0
- package/dist/agent-src/skills/brand-audit/SKILL.md +67 -0
- package/dist/agent-src/skills/brand-audit/evals/triggers.json +17 -0
- package/dist/agent-src/skills/brand-identity/SKILL.md +101 -0
- package/dist/agent-src/skills/brand-identity/evals/triggers.json +17 -0
- package/dist/agent-src/skills/brand-strategy/SKILL.md +83 -0
- package/dist/agent-src/skills/brand-strategy/evals/triggers.json +17 -0
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +102 -0
- package/dist/agent-src/skills/brand-to-tokens/evals/triggers.json +17 -0
- package/dist/agent-src/skills/brand-to-tokens/templates/marp-brand-deck.md.example +46 -0
- package/dist/agent-src/skills/brand-to-tokens/templates/reveal-brand-deck.yaml +32 -0
- package/dist/agent-src/skills/canvas-design/evals/triggers.json +1 -0
- package/dist/agent-src/skills/check-refs/SKILL.md +5 -5
- package/dist/agent-src/skills/code-review/SKILL.md +6 -15
- package/dist/agent-src/skills/command-routing/SKILL.md +1 -1
- package/dist/agent-src/skills/command-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/complexity-first-planning/SKILL.md +96 -0
- package/dist/agent-src/skills/complexity-first-planning/evals/triggers.json +17 -0
- package/dist/agent-src/skills/context-authoring/SKILL.md +2 -2
- package/dist/agent-src/skills/context-document/SKILL.md +35 -2
- package/dist/agent-src/skills/copilot-config/SKILL.md +3 -4
- package/dist/agent-src/skills/corpus-grounding/evals/triggers.json +1 -0
- package/dist/agent-src/skills/corpus-grounding/scripts/bm25_search.ts +482 -0
- package/dist/agent-src/skills/corpus-grounding/scripts/decision_engine.ts +803 -0
- package/dist/agent-src/skills/corpus-grounding/scripts/ground.ts +541 -0
- package/dist/agent-src/skills/corpus-grounding/scripts/schema_validator.ts +309 -0
- package/dist/agent-src/skills/database/SKILL.md +26 -4
- package/dist/agent-src/skills/decision-record/SKILL.md +1 -1
- package/dist/agent-src/skills/decision-record/evals/triggers.json +17 -0
- package/dist/agent-src/skills/decision-review/SKILL.md +179 -0
- package/dist/agent-src/skills/defense-in-depth/SKILL.md +1 -1
- package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
- package/dist/agent-src/skills/design-intelligence/SKILL.md +1 -1
- package/dist/agent-src/skills/design-intelligence/data/manifest.json +23 -6
- package/dist/agent-src/skills/design-intelligence/evals/triggers.json +1 -0
- package/dist/agent-src/skills/design-tokens/evals/triggers.json +1 -0
- package/dist/agent-src/skills/design-tokens/scripts/tokens.ts +888 -0
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +5 -4
- package/dist/agent-src/skills/doc-coauthoring/evals/triggers.json +1 -0
- package/dist/agent-src/skills/eloquent/evals/triggers.json +1 -0
- package/dist/agent-src/skills/emit-tickets/SKILL.md +198 -0
- package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/evals/triggers.json +1 -0
- package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/SKILL.md +33 -0
- package/dist/agent-src/skills/guideline-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/iconography/SKILL.md +88 -0
- package/dist/agent-src/skills/iconography/evals/triggers.json +17 -0
- package/dist/agent-src/skills/image-analyser/evals/triggers.json +1 -0
- package/dist/agent-src/skills/image-creator/evals/triggers.json +1 -0
- package/dist/agent-src/skills/image-editing/SKILL.md +100 -0
- package/dist/agent-src/skills/image-editing/evals/triggers.json +17 -0
- package/dist/agent-src/skills/image-generation/SKILL.md +95 -0
- package/dist/agent-src/skills/image-generation/evals/triggers.json +17 -0
- package/dist/agent-src/skills/image-provider-routing/SKILL.md +96 -0
- package/dist/agent-src/skills/image-provider-routing/evals/triggers.json +17 -0
- package/dist/agent-src/skills/launch-readiness/SKILL.md +21 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +12 -8
- package/dist/agent-src/skills/lint-skills/SKILL.md +5 -5
- package/dist/agent-src/skills/logo-generation/SKILL.md +98 -0
- package/dist/agent-src/skills/logo-generation/evals/triggers.json +17 -0
- package/dist/agent-src/skills/markitdown/SKILL.md +1 -1
- package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
- package/dist/agent-src/skills/md-language-check/SKILL.md +1 -1
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +63 -17
- package/dist/agent-src/skills/motion-choreographer/SKILL.md +1 -1
- package/dist/agent-src/skills/php-coder/evals/triggers.json +1 -0
- package/dist/agent-src/skills/prediction-pool-optimizer/evals/triggers.json +1 -0
- package/dist/agent-src/skills/premortem/SKILL.md +137 -0
- package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +115 -0
- package/dist/agent-src/skills/prompt-engineering-image/evals/triggers.json +17 -0
- package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-validator/evals/triggers.json +1 -0
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +12 -5
- package/dist/agent-src/skills/react-shadcn-ui/scripts/shadcn_add.ts +388 -0
- package/dist/agent-src/skills/readme-writing-package/SKILL.md +1 -1
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +119 -0
- package/dist/agent-src/skills/reasoning-orchestrator/evals/triggers.json +17 -0
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +6 -6
- package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/evals/triggers.json +1 -0
- package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
- package/dist/agent-src/skills/roadmap-management/SKILL.md +16 -3
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +76 -0
- package/dist/agent-src/skills/root-cause-frameworks/SKILL.md +146 -0
- package/dist/agent-src/skills/rule-refactor/SKILL.md +9 -9
- package/dist/agent-src/skills/rule-writing/SKILL.md +7 -7
- package/dist/agent-src/skills/script-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/secrets-management/SKILL.md +1 -1
- package/dist/agent-src/skills/security-audit/SKILL.md +5 -0
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +19 -3
- package/dist/agent-src/skills/skill-management/SKILL.md +3 -3
- package/dist/agent-src/skills/skill-reviewer/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/SKILL.md +5 -5
- package/dist/agent-src/skills/skill-writing/evals/triggers.json +1 -0
- package/dist/agent-src/skills/source-discovery/SKILL.md +182 -0
- package/dist/agent-src/skills/standards-from-config/SKILL.md +93 -0
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +10 -3
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +7 -0
- package/dist/agent-src/skills/tailwind-engineer/scripts/tailwind_config_gen.ts +561 -0
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
- package/dist/agent-src/skills/threat-modeling/SKILL.md +1 -0
- package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
- package/dist/agent-src/skills/typography-system/SKILL.md +138 -0
- package/dist/agent-src/skills/typography-system/evals/triggers.json +17 -0
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -3
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +209 -0
- package/dist/agent-src/skills/verify-repair-loop/evals/output-schema.yml +20 -0
- package/dist/agent-src/skills/verify-repair-loop/evals/triggers.json +17 -0
- package/dist/agent-src/templates/agent-settings.md +7 -0
- package/dist/agent-src/templates/agents/.gitattributes.fragment +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +4 -4
- package/dist/agent-src/templates/contexts/knowledge-card.md +69 -0
- package/dist/agent-src/templates/contexts/lesson-card.md +73 -0
- package/dist/agent-src/templates/roadmaps.md +29 -1
- package/dist/agent-src/templates/scripts/README.md +6 -6
- package/dist/agent-src/templates/scripts/check_memory.ts +640 -0
- package/dist/agent-src/templates/scripts/check_memory_proposal.ts +351 -0
- package/dist/agent-src/templates/scripts/implement_ticket/__main__.ts +27 -0
- package/dist/agent-src/templates/scripts/memory_hash.ts +333 -0
- package/dist/agent-src/templates/scripts/memory_lookup.ts +1067 -0
- package/dist/agent-src/templates/scripts/memory_report.ts +846 -0
- package/dist/agent-src/templates/scripts/memory_signal.ts +422 -0
- package/dist/agent-src/templates/scripts/memory_status.ts +191 -0
- package/dist/agent-src/templates/scripts/pr_review_routing.ts +523 -0
- package/dist/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/dist/agent-src/templates/scripts/telemetry/boundary.ts +164 -0
- package/dist/agent-src/templates/scripts/telemetry/engagement.ts +479 -0
- package/dist/agent-src/templates/scripts/telemetry/report_renderer.ts +394 -0
- package/dist/agent-src/templates/scripts/telemetry/settings.ts +210 -0
- package/dist/agent-src/templates/scripts/telemetry_record.ts +255 -0
- package/dist/agent-src/templates/scripts/telemetry_report.ts +189 -0
- package/dist/agent-src/templates/scripts/telemetry_status.ts +312 -0
- package/dist/agent-src/templates/scripts/tier_usage_report.ts +597 -0
- package/dist/agent-src/templates/scripts/work_engine/__main__.ts +14 -0
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +1118 -0
- package/dist/agent-src/templates/scripts/work_engine/_lib/user_global_paths.ts +329 -0
- package/dist/agent-src/templates/scripts/work_engine/cli.ts +206 -0
- package/dist/agent-src/templates/scripts/work_engine/cli_args.ts +249 -0
- package/dist/agent-src/templates/scripts/work_engine/delivery_state.ts +225 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/analyze.ts +125 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +189 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +94 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/memory.ts +193 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/plan.ts +267 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/refine.ts +518 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/report.ts +379 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +268 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +258 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/index.ts +32 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/contract.ts +243 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/index.ts +108 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +259 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/ui.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/_passthrough.ts +40 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +241 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +216 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +506 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +325 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/index.ts +102 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +462 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +474 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +352 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.ts +33 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.ts +213 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/index.ts +111 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.ts +126 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/report.ts +112 -0
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/test.ts +164 -0
- package/dist/agent-src/templates/scripts/work_engine/dispatcher.ts +515 -0
- package/dist/agent-src/templates/scripts/work_engine/emitters.ts +119 -0
- package/dist/agent-src/templates/scripts/work_engine/errors.ts +24 -0
- package/dist/agent-src/templates/scripts/work_engine/hook_bootstrap.ts +104 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.ts +176 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.ts +41 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.ts +89 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.ts +193 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +304 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.ts +110 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.ts +118 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/index.ts +17 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +161 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.ts +45 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/trace.ts +134 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/context.ts +94 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/events.ts +58 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/exceptions.ts +85 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/index.ts +27 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/registry.ts +66 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/runner.ts +90 -0
- package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +260 -0
- package/dist/agent-src/templates/scripts/work_engine/input_builders.ts +260 -0
- package/dist/agent-src/templates/scripts/work_engine/intent/classify.ts +466 -0
- package/dist/agent-src/templates/scripts/work_engine/migration/v0_to_v1.ts +531 -0
- package/dist/agent-src/templates/scripts/work_engine/orchestration.ts +366 -0
- package/dist/agent-src/templates/scripts/work_engine/persona_policy.ts +97 -0
- package/dist/agent-src/templates/scripts/work_engine/resolvers/diff.ts +135 -0
- package/dist/agent-src/templates/scripts/work_engine/resolvers/file.ts +175 -0
- package/dist/agent-src/templates/scripts/work_engine/resolvers/prompt.ts +115 -0
- package/dist/agent-src/templates/scripts/work_engine/scoring/confidence.ts +415 -0
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +466 -0
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_trace.ts +298 -0
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +444 -0
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +252 -0
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +745 -0
- package/dist/agent-src/templates/scripts/work_engine/state.ts +1151 -0
- package/dist/agent-src/templates/scripts/work_engine/state_io.ts +413 -0
- package/dist/agent-src/templates/tickets.md +120 -0
- package/dist/cli/agent-config.js +31 -300
- package/dist/cli/agent-config.js.map +1 -1
- package/dist/cli/commands/commands.js +11 -6
- package/dist/cli/commands/commands.js.map +1 -1
- package/dist/cli/commands/doctorShell.js +4 -22
- package/dist/cli/commands/doctorShell.js.map +1 -1
- package/dist/cli/commands/packs.js +1 -1
- package/dist/cli/commands/packs.js.map +1 -1
- package/dist/cli/commands/recordTriggerEval.js +179 -0
- package/dist/cli/commands/recordTriggerEval.js.map +1 -0
- package/dist/cli/commands/recordTriggerEval.test.js +113 -0
- package/dist/cli/commands/recordTriggerEval.test.js.map +1 -0
- package/dist/cli/commands/workspaces.js +1 -1
- package/dist/cli/commands/workspaces.js.map +1 -1
- package/dist/cli/discovery/loadManifest.js.map +1 -1
- package/dist/cli/main.js +330 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/python/knowledge_ingest.js +1048 -0
- package/dist/cli/python/knowledge_ingest.js.map +1 -0
- package/dist/cli/python/workspace_analytics.js +1085 -0
- package/dist/cli/python/workspace_analytics.js.map +1 -0
- package/dist/cli/python/workspace_crypto.js +544 -0
- package/dist/cli/python/workspace_crypto.js.map +1 -0
- package/dist/cli/python/workspace_documents.js +1216 -0
- package/dist/cli/python/workspace_documents.js.map +1 -0
- package/dist/cli/python/workspace_drive.js +574 -0
- package/dist/cli/python/workspace_drive.js.map +1 -0
- package/dist/cli/python/workspace_drive_health.js +628 -0
- package/dist/cli/python/workspace_drive_health.js.map +1 -0
- package/dist/cli/python/workspace_explain.js +765 -0
- package/dist/cli/python/workspace_explain.js.map +1 -0
- package/dist/cli/python/workspace_hosts.js +349 -0
- package/dist/cli/python/workspace_hosts.js.map +1 -0
- package/dist/cli/python/workspace_inbox.js +692 -0
- package/dist/cli/python/workspace_inbox.js.map +1 -0
- package/dist/cli/python/workspace_render.js +816 -0
- package/dist/cli/python/workspace_render.js.map +1 -0
- package/dist/cli/python/workspace_roles.js +487 -0
- package/dist/cli/python/workspace_roles.js.map +1 -0
- package/dist/cli/python/workspace_secrets.js +180 -0
- package/dist/cli/python/workspace_secrets.js.map +1 -0
- package/dist/cli/python/workspace_sessions.js +1079 -0
- package/dist/cli/python/workspace_sessions.js.map +1 -0
- package/dist/cli/python/workspace_skills.js +417 -0
- package/dist/cli/python/workspace_skills.js.map +1 -0
- package/dist/cli/registry.js +2 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +1802 -448
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +12 -6
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +303 -43
- package/dist/discovery/trust-report.md +4 -4
- package/dist/discovery/workspaces.json +127 -41
- package/dist/install/install.mjs +13934 -0
- package/dist/mcp/registry-manifest.json +4 -4
- package/dist/router.json +1 -1
- package/dist/server/routes/wizard.js +54 -24
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/server/routes/workspace.js +44 -25
- package/dist/server/routes/workspace.js.map +1 -1
- package/dist/server/schemas/settings.js +33 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/SKILL_CENSUS.md +344 -0
- package/docs/adrs/cost/0001-hard-stop-hook.md +5 -5
- package/docs/adrs/memory/0001-consumer-side-snapshot.md +15 -7
- package/docs/adrs/memory/README.md +6 -5
- package/docs/adrs/router/0001-three-tier-routing.md +2 -2
- package/docs/adrs/schema/0001-json-schema-frontmatter.md +2 -2
- package/docs/adrs/smoke/0001-per-tier-smoke-scripts.md +5 -5
- package/docs/adrs/telegraph/0001-default-off-until-bench.md +3 -3
- package/docs/architecture/augment-projection.md +1 -1
- package/docs/architecture/multi-tool-projection.md +3 -3
- package/docs/architecture.md +42 -11
- package/docs/archive/CHANGELOG-pre-2.2.0.md +30 -30
- package/docs/archive/CHANGELOG-pre-2.25.0.md +1 -1
- package/docs/archive/CHANGELOG-pre-4.5.0.md +1 -1
- package/docs/archive/CHANGELOG-pre-6.0.0.md +473 -0
- package/docs/benchmark.md +51 -53
- package/docs/benchmarks.md +2 -2
- package/docs/capability-matrix.md +32 -0
- package/docs/case-studies/frontend-design-positioning.md +86 -0
- package/docs/catalog.md +63 -15
- package/docs/command-flows.md +90 -92
- package/docs/command-naming-audit.md +60 -0
- package/docs/contracts/STABILITY.md +32 -0
- package/docs/contracts/adr-layout.md +2 -3
- package/docs/contracts/adr-level-6-productization.md +1 -1
- package/docs/contracts/agents-md-tech-stack.md +1 -1
- package/docs/contracts/ai-council-config.md +64 -29
- package/docs/contracts/analysis-memory-loop.md +149 -0
- package/docs/contracts/benchmark-ab-contract.md +3 -3
- package/docs/contracts/branch-protection-policy.md +27 -0
- package/docs/contracts/brand-token-consumption.md +69 -0
- package/docs/contracts/command-clusters.md +3 -2
- package/docs/contracts/command-surface-tiers.md +13 -0
- package/docs/contracts/cost-enforcement.md +1 -1
- package/docs/contracts/cost-summary-schema.md +1 -1
- package/docs/contracts/daily-workspace.md +1 -0
- package/docs/contracts/discovery-manifest.schema.json +25 -4
- package/docs/contracts/explain-modes.md +1 -1
- package/docs/contracts/implement-ticket-flow.md +15 -16
- package/docs/contracts/install-layout.md +249 -0
- package/docs/contracts/kernel-membership.md +1 -1
- package/docs/contracts/linear-ai-rules-inclusion.md +2 -2
- package/docs/contracts/linter-structural-model.md +1 -1
- package/docs/contracts/mcp-discovery-phase-notice.md +1 -1
- package/docs/contracts/mcp-tool-inventory.md +10 -10
- package/docs/contracts/measurement-baseline.md +1 -1
- package/docs/contracts/memory-visibility-v1.md +1 -5
- package/docs/contracts/multi-tool-projection-fidelity.md +1 -1
- package/docs/contracts/namespace.md +3 -3
- package/docs/contracts/no-runtime-boundary.md +56 -0
- package/docs/contracts/package-self-orientation.md +24 -0
- package/docs/contracts/persona-schema.md +1 -1
- package/docs/contracts/provider-lifecycle.md +3 -3
- package/docs/contracts/reasoning-discipline-protocol.md +83 -0
- package/docs/contracts/rule-classification.md +3 -3
- package/docs/contracts/rule-interactions.md +1 -1
- package/docs/contracts/skill-domains.md +1 -1
- package/docs/contracts/smoke-contracts.md +2 -2
- package/docs/contracts/surface-tiers.md +81 -0
- package/docs/contracts/ticket-bundle-format.md +228 -0
- package/docs/contracts/universal-skills.md +0 -1
- package/docs/contracts/workspace-boundary.md +84 -0
- package/docs/cookbook.md +152 -0
- package/docs/customization.md +15 -4
- package/docs/decisions/ADR-009-event4u-namespace.md +1 -1
- package/docs/decisions/ADR-013-discovery-frontmatter-contract.md +17 -1
- package/docs/decisions/ADR-026-explain-mode-translation.md +1 -1
- package/docs/decisions/ADR-056-unvalidated-video-adapters-disposition.md +1 -1
- package/docs/decisions/ADR-059-render-resume-filesystem-as-state.md +1 -1
- package/docs/decisions/ADR-060-comfyui-sandbox-model.md +1 -1
- package/docs/decisions/ADR-061-corpus-grounding-layer.md +48 -1
- package/docs/decisions/ADR-088-no-external-runtime-federation.md +26 -27
- package/docs/decisions/ADR-090-visibility-command-frontmatter-field.md +95 -0
- package/docs/decisions/ADR-091-split-meta-capability-packs.md +113 -0
- package/docs/decisions/ADR-092-defer-command-tier-alias-removal.md +93 -0
- package/docs/decisions/ADR-093-ai-council-config-user-global.md +111 -0
- package/docs/decisions/ADR-094-agent-memory-layer-removal.md +94 -0
- package/docs/decisions/ADR-095-workspace-boundary-contract.md +108 -0
- package/docs/decisions/ADR-096-analysis-workbench.md +110 -0
- package/docs/decisions/ADR-097-mission-recipe-privilege-boundary.md +121 -0
- package/docs/decisions/ADR-098-evidence-first-structure-discovery.md +154 -0
- package/docs/decisions/ADR-099-file-first-pattern-library.md +87 -0
- package/docs/decisions/ADR-100-global-knowledge-card-sharing.md +133 -0
- package/docs/decisions/ADR-101-ticket-bundle-emission.md +109 -0
- package/docs/decisions/ADR-102-ticket-handoff-paste-and-mcp.md +72 -0
- package/docs/decisions/ADR-103-global-knowledge-default-off-until-measured.md +92 -0
- package/docs/decisions/ADR-200-python-to-typescript-migration.md +193 -0
- package/docs/decisions/INDEX.md +15 -0
- package/docs/development.md +5 -7
- package/docs/distribution/mcp-submission-checklist.md +3 -3
- package/docs/featured-commands.md +1 -1
- package/docs/featured-skills.md +1 -1
- package/docs/getting-started-by-role.md +2 -0
- package/docs/getting-started.md +4 -4
- package/docs/guidelines/agent-infra/5w2h-analysis.md +1 -1
- package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
- package/docs/guidelines/agent-infra/corpus-grounding-authoring.md +1 -1
- package/docs/guidelines/agent-infra/critical-thinking.md +1 -1
- package/docs/guidelines/agent-infra/engineering-memory-data-format.md +1 -5
- package/docs/guidelines/agent-infra/failure-signatures.md +35 -0
- package/docs/guidelines/agent-infra/first-principles.md +1 -1
- package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +169 -0
- package/docs/guidelines/agent-infra/inversion-thinking.md +1 -1
- package/docs/guidelines/agent-infra/ios-simulator-guide.md +9 -14
- package/docs/guidelines/agent-infra/mcp-request-signing.md +19 -22
- package/docs/guidelines/agent-infra/memory-access.md +25 -31
- package/docs/guidelines/agent-infra/mental-models.md +1 -1
- package/docs/guidelines/agent-infra/model-recommendation.md +29 -0
- package/docs/guidelines/agent-infra/scqa-framework.md +3 -3
- package/docs/guidelines/agent-infra/security-lint-containment.md +81 -0
- package/docs/guidelines/agent-infra/six-hats.md +1 -1
- package/docs/guidelines/agent-infra/size-and-scope.md +17 -0
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +2 -2
- package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +72 -0
- package/docs/guides/frontend-design-corpus-refresh.md +83 -0
- package/docs/guides/skill-preview.md +1 -1
- package/docs/hook-payload-capture.md +4 -4
- package/docs/installation.md +1 -1
- package/docs/mcp.md +3 -3
- package/docs/migration/consumer-template-consumption-model.md +145 -0
- package/docs/migration/divergences/README.md +55 -0
- package/docs/migration/divergences/_template.md +50 -0
- package/docs/migration/divergences/bench-stats-float-precision.md +72 -0
- package/docs/migration/divergences/mcp-telemetry-node-sqlite.md +61 -0
- package/docs/migration/divergences/pack-mcp-content-gzip-body.md +53 -0
- package/docs/migration/divergences/src-scripts-build_cloud_bundle.md +63 -0
- package/docs/migration/divergences/src-scripts-check_memory.md +91 -0
- package/docs/migration/divergences/src-scripts-inventory_abstraction_budget.md +65 -0
- package/docs/migration/divergences/src-scripts-lint_marketplace.md +57 -0
- package/docs/migration/divergences/src-scripts-lint_mcp_registry_manifest.md +70 -0
- package/docs/migration/divergences/src-scripts-spotcheck_thin_root.md +60 -0
- package/docs/migration/divergences/src-scripts-validate_agent_settings.md +58 -0
- package/docs/migration/node-floor.md +86 -0
- package/docs/migration/yaml-roundtrip-spike.md +163 -0
- package/docs/parity/bench-external.json +58 -0
- package/docs/parity/external-runtime.md +46 -0
- package/docs/personas.md +6 -1
- package/docs/quality.md +3 -3
- package/docs/role-experiences.md +19 -0
- package/docs/safety.md +3 -3
- package/docs/setup/per-ide/windsurf.md +1 -1
- package/docs/skills-catalog.md +26 -2
- package/docs/threat-model.md +28 -0
- package/llms.txt +25 -1
- package/package.json +10 -15
- package/src/config/agent-settings.template.yml +128 -3
- package/src/config/discovery/packs.yml +60 -0
- package/src/config/discovery/unassigned-artefacts.yml +6 -0
- package/src/config/discovery/workspaces.yml +5 -3
- package/src/config/gitignore-block.txt +13 -0
- package/src/scripts/_cli/cmd_doctor.ts +2306 -0
- package/src/scripts/_cli/cmd_explain.ts +748 -0
- package/src/scripts/_cli/cmd_export.ts +375 -0
- package/src/scripts/_cli/cmd_migrate.ts +951 -0
- package/src/scripts/_cli/cmd_prune.ts +610 -0
- package/src/scripts/_cli/cmd_refresh.ts +530 -0
- package/src/scripts/_cli/cmd_settings_check.ts +407 -0
- package/src/scripts/_cli/cmd_settings_migrate.ts +344 -0
- package/src/scripts/_cli/cmd_sync.ts +381 -0
- package/src/scripts/_cli/cmd_uninstall.ts +833 -0
- package/src/scripts/_cli/cmd_update.ts +585 -0
- package/src/scripts/_cli/cmd_upgrade.ts +390 -0
- package/src/scripts/_cli/cmd_validate.ts +394 -0
- package/src/scripts/_cli/cmd_versions.ts +492 -0
- package/src/scripts/_cli/explain_last/assumptions.ts +114 -0
- package/src/scripts/_cli/explain_last/council.ts +197 -0
- package/src/scripts/_cli/explain_last/halt.ts +73 -0
- package/src/scripts/_cli/explain_last/index.ts +155 -0
- package/src/scripts/_cli/explain_last/inputs.ts +211 -0
- package/src/scripts/_cli/explain_last/memory.ts +231 -0
- package/src/scripts/_cli/explain_last/provider.ts +82 -0
- package/src/scripts/_cli/explain_last/render.ts +54 -0
- package/src/scripts/_cli/explain_last/route.ts +70 -0
- package/src/scripts/_cli/explain_last/scrubber.ts +138 -0
- package/src/scripts/_cli/explain_last/sections/assumptions.ts +51 -0
- package/src/scripts/_cli/explain_last/sections/council.ts +56 -0
- package/src/scripts/_cli/explain_last/sections/halt.ts +60 -0
- package/src/scripts/_cli/explain_last/sections/header.ts +50 -0
- package/src/scripts/_cli/explain_last/sections/index.ts +21 -0
- package/src/scripts/_cli/explain_last/sections/inputs.ts +63 -0
- package/src/scripts/_cli/explain_last/sections/memory.ts +124 -0
- package/src/scripts/_cli/explain_last/sections/pack.ts +42 -0
- package/src/scripts/_cli/explain_last/sections/provider.ts +51 -0
- package/src/scripts/_cli/explain_last/sections/route.ts +48 -0
- package/src/scripts/_cli/explain_last/state_loader.ts +119 -0
- package/src/scripts/_dispatch.bash +179 -163
- package/src/scripts/_lib/agent_settings.ts +1123 -0
- package/src/scripts/_lib/agent_src.ts +654 -0
- package/src/scripts/_lib/agents_overlay.ts +183 -0
- package/src/scripts/_lib/bench_ab_cache.ts +399 -0
- package/src/scripts/_lib/bench_ab_scoring.ts +352 -0
- package/src/scripts/_lib/bench_ab_scoring_v2.ts +751 -0
- package/src/scripts/_lib/bench_cost.ts +396 -0
- package/src/scripts/_lib/bench_quality.ts +237 -0
- package/src/scripts/_lib/bench_report.ts +255 -0
- package/src/scripts/_lib/bench_telegraph.ts +516 -0
- package/src/scripts/_lib/bench_telegraph_report.ts +272 -0
- package/src/scripts/_lib/changelog_eras.ts +398 -0
- package/src/scripts/_lib/claude_desktop_bundler.ts +324 -0
- package/src/scripts/_lib/cli_wrapper.ts +89 -0
- package/src/scripts/_lib/fs_atomic.ts +172 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +639 -0
- package/src/scripts/_lib/install_layout.ts +87 -0
- package/src/scripts/_lib/install_regenerator.ts +157 -0
- package/src/scripts/_lib/installed_lock.ts +451 -0
- package/src/scripts/_lib/installed_tools.ts +518 -0
- package/src/scripts/_lib/json_pointers.ts +388 -0
- package/src/scripts/_lib/knowledge_global.ts +770 -0
- package/src/scripts/_lib/knowledge_global_promote.ts +453 -0
- package/src/scripts/_lib/knowledge_global_redaction.ts +448 -0
- package/src/scripts/_lib/link_crypto.ts +325 -0
- package/src/scripts/_lib/linked_projects.ts +613 -0
- package/src/scripts/_lib/model_tier.ts +65 -0
- package/src/scripts/_lib/module_detection.ts +275 -0
- package/src/scripts/_lib/node_sqlite.d.ts +32 -0
- package/src/scripts/_lib/pin_resolver.ts +264 -0
- package/src/scripts/_lib/py_random.ts +212 -0
- package/src/scripts/_lib/script_output.ts +147 -0
- package/src/scripts/_lib/security_lint.ts +623 -0
- package/src/scripts/_lib/surface_tiers.ts +127 -0
- package/src/scripts/_lib/token_count.ts +126 -0
- package/src/scripts/_lib/update_check.ts +297 -0
- package/src/scripts/_lib/user_global_paths.ts +329 -0
- package/src/scripts/_lib/value_ladder.ts +882 -0
- package/src/scripts/_lib/value_report.ts +617 -0
- package/src/scripts/_lib/zip_min.ts +175 -0
- package/src/scripts/adoption_report.ts +357 -0
- package/src/scripts/adoption_snapshot.ts +392 -0
- package/src/scripts/adoption_status.ts +424 -0
- package/src/scripts/adr/regenerate_index.ts +257 -0
- package/src/scripts/ai-image/adapters/flux.sh +45 -0
- package/src/scripts/ai-image/adapters/gemini-image.sh +45 -0
- package/src/scripts/ai-image/adapters/ideogram.sh +45 -0
- package/src/scripts/ai-image/adapters/recraft.sh +47 -0
- package/src/scripts/ai-video/adapters/comfyui.sh +3 -3
- package/src/scripts/ai-video/adapters/fal.sh +3 -3
- package/src/scripts/ai-video/adapters/gemini-veo.sh +3 -3
- package/src/scripts/ai-video/adapters/higgsfield.sh +3 -3
- package/src/scripts/ai-video/adapters/kling.sh +3 -3
- package/src/scripts/ai-video/adapters/musetalk.sh +2 -2
- package/src/scripts/ai-video/adapters/openai-images.sh +3 -3
- package/src/scripts/ai-video/adapters/replicate.sh +3 -3
- package/src/scripts/ai-video/adapters/sora.sh +3 -3
- package/src/scripts/ai-video/adapters/syncso.sh +3 -3
- package/src/scripts/ai-video/audio-adapters/allin1.sh +2 -2
- package/src/scripts/ai-video/audio-adapters/whisperx.sh +2 -2
- package/src/scripts/ai-video/lib/audio-adapter-contract.md +1 -1
- package/src/scripts/ai-video/lib/embed-provenance.sh +2 -2
- package/src/scripts/ai-video/lib/ingest-song.sh +2 -2
- package/src/scripts/ai-video/lib/parse-blueprint.sh +1 -1
- package/src/scripts/ai-video/lib/resume-scan.sh +2 -2
- package/src/scripts/ai-video/smoke-trace.sh +16 -7
- package/src/scripts/ai-video/stitch.sh +2 -2
- package/src/scripts/ai_council/_default_prices.ts +73 -0
- package/src/scripts/ai_council/advisors.ts +244 -0
- package/src/scripts/ai_council/airgap.ts +249 -0
- package/src/scripts/ai_council/budget_guard.ts +492 -0
- package/src/scripts/ai_council/bundler.ts +376 -0
- package/src/scripts/ai_council/cli_hints.ts +120 -0
- package/src/scripts/ai_council/clients.ts +2214 -0
- package/src/scripts/ai_council/compile_corpus.ts +681 -0
- package/src/scripts/ai_council/confidence_gate.ts +230 -0
- package/src/scripts/ai_council/config.ts +1729 -0
- package/src/scripts/ai_council/consensus.ts +551 -0
- package/src/scripts/ai_council/events_log.ts +327 -0
- package/src/scripts/ai_council/learn_low_impact_preview.ts +317 -0
- package/src/scripts/ai_council/low_impact.ts +1069 -0
- package/src/scripts/ai_council/low_impact_corpus.ts +662 -0
- package/src/scripts/ai_council/low_impact_intake.ts +222 -0
- package/src/scripts/ai_council/modes.ts +169 -0
- package/src/scripts/ai_council/necessity.ts +933 -0
- package/src/scripts/ai_council/orchestrator.ts +1689 -0
- package/src/scripts/ai_council/pricing.ts +267 -0
- package/src/scripts/ai_council/probation_gate.ts +282 -0
- package/src/scripts/ai_council/project_context.ts +308 -0
- package/src/scripts/ai_council/prompts.ts +600 -0
- package/src/scripts/ai_council/redact_low_impact_entry.ts +291 -0
- package/src/scripts/ai_council/replay.ts +314 -0
- package/src/scripts/ai_council/session.ts +558 -0
- package/src/scripts/ai_council/shadow_dispatch.ts +509 -0
- package/src/scripts/ai_council/solo_dispatch.ts +281 -0
- package/src/scripts/analysis_freshness.ts +343 -0
- package/src/scripts/annotate_discovery.ts +288 -0
- package/src/scripts/apply_modules_config.ts +537 -0
- package/src/scripts/audit_adr_coverage.ts +357 -0
- package/src/scripts/audit_auto_rules.ts +415 -0
- package/src/scripts/audit_cloud_compatibility.ts +608 -0
- package/src/scripts/audit_command_surface.ts +1227 -0
- package/src/scripts/audit_initial_context.ts +694 -0
- package/src/scripts/audit_likelihood.ts +434 -0
- package/src/scripts/audit_mcp_tools.ts +252 -0
- package/src/scripts/audit_overlap.ts +421 -0
- package/src/scripts/audit_skill_descriptions.ts +402 -0
- package/src/scripts/audit_skill_overlap.ts +576 -0
- package/src/scripts/audit_user_type_axis.ts +264 -0
- package/src/scripts/backfill_model_tier.ts +349 -0
- package/src/scripts/bench_ab_cache_dispatch.ts +126 -0
- package/src/scripts/bench_ab_clone.ts +610 -0
- package/src/scripts/bench_ab_diff.ts +609 -0
- package/src/scripts/bench_ab_integrity.ts +261 -0
- package/src/scripts/bench_ab_run.ts +417 -0
- package/src/scripts/bench_ab_task_runner.ts +1382 -0
- package/src/scripts/bench_ab_tracka_run.ts +436 -0
- package/src/scripts/bench_ab_v2_run.ts +585 -0
- package/src/scripts/bench_ab_v2_stats.ts +1018 -0
- package/src/scripts/bench_baseline_ready.ts +326 -0
- package/src/scripts/bench_condense_memory.ts +479 -0
- package/src/scripts/bench_drift_check.ts +503 -0
- package/src/scripts/bench_per_tool.ts +591 -0
- package/src/scripts/bench_rtk_savings.ts +710 -0
- package/src/scripts/bench_run.ts +509 -0
- package/src/scripts/bench_runner.ts +519 -0
- package/src/scripts/build_cloud_bundle.ts +692 -0
- package/src/scripts/build_discovery_manifest.ts +1371 -0
- package/src/scripts/build_linear_digest.ts +368 -0
- package/src/scripts/build_mcp_registry_manifest.ts +351 -0
- package/src/scripts/build_rule_trigger_matrix.ts +469 -0
- package/src/scripts/capture_showcase_session.ts +735 -0
- package/src/scripts/chat_history.ts +2301 -0
- package/src/scripts/check_always_budget.ts +694 -0
- package/src/scripts/check_artefact_checksums.ts +281 -0
- package/src/scripts/check_augment_description_cap.ts +133 -0
- package/src/scripts/check_augmentignore.ts +108 -0
- package/src/scripts/check_beta_review_markers.ts +234 -0
- package/src/scripts/check_bite_sized_granularity.ts +116 -0
- package/src/scripts/check_cluster_patterns.ts +285 -0
- package/src/scripts/check_command_count_messaging.ts +224 -0
- package/src/scripts/check_condensation.ts +900 -0
- package/src/scripts/check_condensed_paths.ts +414 -0
- package/src/scripts/check_context_paths.ts +388 -0
- package/src/scripts/check_council_config_location.ts +260 -0
- package/src/scripts/check_council_layout.ts +180 -0
- package/src/scripts/check_council_references.ts +345 -0
- package/src/scripts/check_discovery_determinism.ts +124 -0
- package/src/scripts/check_gate_paths.ts +230 -0
- package/src/scripts/check_iron_law_prominence.ts +298 -0
- package/src/scripts/check_kernel_rule_bundle.ts +242 -0
- package/src/scripts/check_knowledge_cards.ts +759 -0
- package/src/scripts/check_md_language.ts +291 -0
- package/src/scripts/check_memory.ts +845 -0
- package/src/scripts/check_memory_proposal.ts +351 -0
- package/src/scripts/check_module_management_neutral.ts +238 -0
- package/src/scripts/check_no_conflict_markers.ts +298 -0
- package/src/scripts/check_no_conflict_markers_allowlist.json +4 -0
- package/src/scripts/check_no_external_sources.ts +351 -0
- package/src/scripts/check_no_local_settings_committed.ts +69 -0
- package/src/scripts/check_no_new_legacy_path.ts +188 -0
- package/src/scripts/check_no_roadmap_refs.ts +304 -0
- package/src/scripts/check_one_off_location.ts +165 -0
- package/src/scripts/check_overlay_cascade_subdirs.ts +188 -0
- package/src/scripts/check_portability.ts +860 -0
- package/src/scripts/check_proposal.ts +0 -0
- package/src/scripts/check_public_catalog_links.ts +204 -0
- package/src/scripts/check_public_links.ts +357 -0
- package/src/scripts/check_references.ts +963 -0
- package/src/scripts/check_release_includes_discovery.ts +94 -0
- package/src/scripts/check_release_pr_shape.ts +222 -0
- package/src/scripts/check_release_published.ts +235 -0
- package/src/scripts/check_release_trunk_sync.ts +203 -0
- package/src/scripts/check_reply_consistency.ts +359 -0
- package/src/scripts/check_roadmap_trackable.ts +268 -0
- package/src/scripts/check_role_doc_links.ts +187 -0
- package/src/scripts/check_safety_floor_untouched.ts +160 -0
- package/src/scripts/check_skill_requires.ts +205 -0
- package/src/scripts/check_structural_breaking.ts +170 -0
- package/src/scripts/check_surface_tiers.ts +567 -0
- package/src/scripts/check_template_pin_drift.ts +222 -0
- package/src/scripts/check_test_coverage_diff.ts +235 -0
- package/src/scripts/check_token_optimizer_freshness.ts +183 -0
- package/src/scripts/check_trigger_evals.ts +375 -0
- package/src/scripts/check_update_banner.ts +143 -0
- package/src/scripts/ci_status.ts +0 -0
- package/src/scripts/ci_summary.ts +235 -0
- package/src/scripts/ci_time_ratio.ts +526 -0
- package/src/scripts/command_suggester/cooldown.ts +176 -0
- package/src/scripts/command_suggester/index.ts +41 -0
- package/src/scripts/command_suggester/loader.ts +205 -0
- package/src/scripts/command_suggester/match.ts +294 -0
- package/src/scripts/command_suggester/rank.ts +201 -0
- package/src/scripts/command_suggester/render.ts +122 -0
- package/src/scripts/command_suggester/sanitize.ts +114 -0
- package/src/scripts/command_suggester/settings.ts +186 -0
- package/src/scripts/command_suggester/types.ts +0 -0
- package/src/scripts/compile_router.ts +297 -0
- package/src/scripts/condense.sh +7 -1
- package/src/scripts/condense.ts +2035 -0
- package/src/scripts/condense_memory.ts +334 -0
- package/src/scripts/config/index.ts +15 -0
- package/src/scripts/config/packs.ts +310 -0
- package/src/scripts/config/presets.ts +369 -0
- package/src/scripts/config/profile_explain.ts +114 -0
- package/src/scripts/config/profiles.ts +277 -0
- package/src/scripts/config/session_profiles.ts +1064 -0
- package/src/scripts/context_hygiene_hook.ts +272 -0
- package/src/scripts/cost_by_conversation.ts +444 -0
- package/src/scripts/cost_summary.ts +407 -0
- package/src/scripts/council_cli.ts +2827 -0
- package/src/scripts/council_prune.ts +153 -0
- package/src/scripts/cross_repo_retrieve.ts +694 -0
- package/src/scripts/discovery_stats.ts +218 -0
- package/src/scripts/evidence_report.ts +580 -0
- package/src/scripts/external_sources_denylist.json +92 -0
- package/src/scripts/extract_audit_patterns.ts +394 -0
- package/src/scripts/first_run_gate_hook.ts +246 -0
- package/src/scripts/gen_discovery_baseline.ts +297 -0
- package/src/scripts/generate_capabilities_index.ts +496 -0
- package/src/scripts/generate_capability_matrix.ts +430 -0
- package/src/scripts/generate_catalog.ts +178 -0
- package/src/scripts/generate_command_flows.ts +316 -0
- package/src/scripts/generate_cookbook.ts +302 -0
- package/src/scripts/generate_index.ts +500 -0
- package/src/scripts/generate_ownership_matrix.ts +646 -0
- package/src/scripts/generate_pack_manifests.ts +1025 -0
- package/src/scripts/generate_role_experiences_catalog.ts +265 -0
- package/src/scripts/hermetic-install.sh +22 -11
- package/src/scripts/hook_manifest.yaml +37 -15
- package/src/scripts/hooks/augment-chat-history.sh +3 -10
- package/src/scripts/hooks/augment-context-hygiene.sh +3 -10
- package/src/scripts/hooks/augment-dispatcher.sh +3 -10
- package/src/scripts/hooks/augment-onboarding-gate.sh +3 -10
- package/src/scripts/hooks/augment-roadmap-progress.sh +3 -10
- package/src/scripts/hooks/block_no_verify.ts +413 -0
- package/src/scripts/hooks/cline-dispatcher.sh +3 -10
- package/src/scripts/hooks/cowork-dispatcher.sh +3 -14
- package/src/scripts/hooks/cursor-dispatcher.sh +3 -10
- package/src/scripts/hooks/dispatch_hook.ts +851 -0
- package/src/scripts/hooks/dispatch_issues.ts +226 -0
- package/src/scripts/hooks/envelope.ts +140 -0
- package/src/scripts/hooks/gemini-dispatcher.sh +3 -8
- package/src/scripts/hooks/replay_hook.ts +364 -0
- package/src/scripts/hooks/state_io.ts +293 -0
- package/src/scripts/hooks/windsurf-dispatcher.sh +3 -9
- package/src/scripts/hooks_doctor.ts +418 -0
- package/src/scripts/hooks_status.ts +292 -0
- package/src/scripts/injection_scan_hook.ts +285 -0
- package/src/scripts/install +36 -22
- package/src/scripts/install-hooks.sh +29 -12
- package/src/scripts/install.sh +38 -14
- package/src/scripts/install.ts +4515 -0
- package/src/scripts/inventory_abstraction_budget.ts +1104 -0
- package/src/scripts/inventory_frontmatter.ts +320 -0
- package/src/scripts/inventory_meta_layers.ts +516 -0
- package/src/scripts/iron_law_sha.ts +233 -0
- package/src/scripts/knowledge_global_cli.ts +1105 -0
- package/src/scripts/linked_projects_list.ts +310 -0
- package/src/scripts/lint_agent_security.ts +224 -0
- package/src/scripts/lint_agent_skill_names.ts +241 -0
- package/src/scripts/lint_agents_layout.ts +205 -0
- package/src/scripts/lint_agents_md.ts +294 -0
- package/src/scripts/lint_archived_skills.ts +309 -0
- package/src/scripts/lint_artefact_frontmatter.ts +359 -0
- package/src/scripts/lint_bench_ab.ts +319 -0
- package/src/scripts/lint_bench_corpus.ts +421 -0
- package/src/scripts/lint_command_flow_coverage.ts +231 -0
- package/src/scripts/lint_command_routing.ts +377 -0
- package/src/scripts/lint_command_tiers.ts +345 -0
- package/src/scripts/lint_command_verbs.ts +379 -0
- package/src/scripts/lint_commit_subjects.ts +243 -0
- package/src/scripts/lint_context_spine_usage.ts +198 -0
- package/src/scripts/lint_discovery_manifest.ts +540 -0
- package/src/scripts/lint_discovery_vocabulary.ts +393 -0
- package/src/scripts/lint_empty_roadmaps.ts +147 -0
- package/src/scripts/lint_eval_freshness.ts +335 -0
- package/src/scripts/lint_examples.ts +183 -0
- package/src/scripts/lint_explain_trace.ts +381 -0
- package/src/scripts/lint_featured_skills.ts +0 -0
- package/src/scripts/lint_flows.ts +701 -0
- package/src/scripts/lint_framework_leakage.ts +497 -0
- package/src/scripts/lint_framework_leakage_allowlist.json +8 -1
- package/src/scripts/lint_frontmatter_boilerplate.ts +356 -0
- package/src/scripts/lint_ghostwriter_source.ts +389 -0
- package/src/scripts/lint_global_paths.ts +420 -0
- package/src/scripts/lint_handoffs.ts +362 -0
- package/src/scripts/lint_hidden_unicode.ts +350 -0
- package/src/scripts/lint_hook_concern_budget.ts +319 -0
- package/src/scripts/lint_hook_manifest.ts +354 -0
- package/src/scripts/lint_instruction_smuggling.ts +173 -0
- package/src/scripts/lint_load_context.ts +371 -0
- package/src/scripts/lint_marketplace.ts +286 -0
- package/src/scripts/lint_marketplace_install_completeness.ts +309 -0
- package/src/scripts/lint_mcp_config_security.ts +225 -0
- package/src/scripts/lint_mcp_registry_manifest.ts +350 -0
- package/src/scripts/lint_media_policy_linkage.ts +224 -0
- package/src/scripts/lint_missions.ts +774 -0
- package/src/scripts/lint_model_tier_coverage.ts +151 -0
- package/src/scripts/lint_namespace.ts +295 -0
- package/src/scripts/lint_namespace_collisions.ts +203 -0
- package/src/scripts/lint_new_skill_gate.ts +462 -0
- package/src/scripts/lint_no_new_atomic_commands.ts +342 -0
- package/src/scripts/lint_one_off_age.ts +348 -0
- package/src/scripts/lint_orchestration_dsl.ts +377 -0
- package/src/scripts/lint_orchestrator_auto_detect.ts +177 -0
- package/src/scripts/lint_pack_boundaries.ts +366 -0
- package/src/scripts/lint_pack_dependencies.ts +541 -0
- package/src/scripts/lint_pack_first_win.ts +202 -0
- package/src/scripts/lint_persona_governance.ts +292 -0
- package/src/scripts/lint_positioning.ts +257 -0
- package/src/scripts/lint_profile_overlay_set_only.ts +324 -0
- package/src/scripts/lint_readme_jargon.ts +189 -0
- package/src/scripts/lint_readme_size.ts +73 -0
- package/src/scripts/lint_regression.ts +497 -0
- package/src/scripts/lint_roadmap_ci_steps.ts +252 -0
- package/src/scripts/lint_roadmap_complexity.ts +295 -0
- package/src/scripts/lint_roadmap_later_disposition.ts +357 -0
- package/src/scripts/lint_role_experiences.ts +410 -0
- package/src/scripts/lint_rule_interactions.ts +281 -0
- package/src/scripts/lint_rule_tiers.ts +169 -0
- package/src/scripts/lint_showcase_sessions.ts +254 -0
- package/src/scripts/lint_skill_frontmatter_safety.ts +279 -0
- package/src/scripts/lint_skill_originality.ts +586 -0
- package/src/scripts/lint_skill_originality_allowlist.json +20 -0
- package/src/scripts/lint_skill_tools.ts +320 -0
- package/src/scripts/lint_ticket_buildable.ts +1027 -0
- package/src/scripts/lint_topics_yaml.ts +203 -0
- package/src/scripts/lint_trust_coherence.ts +377 -0
- package/src/scripts/lint_value_dashboard.ts +314 -0
- package/src/scripts/lint_workflow_security.ts +637 -0
- package/src/scripts/lint_workflow_security_allowlist.json +20 -0
- package/src/scripts/lint_workspace_boundary.ts +248 -0
- package/src/scripts/mcp_parity_smoke.ts +638 -0
- package/src/scripts/mcp_render.ts +346 -0
- package/src/scripts/mcp_server/__main__.ts +28 -0
- package/src/scripts/mcp_server/catalog.ts +154 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +2 -3
- package/src/scripts/mcp_server/index.ts +24 -0
- package/src/scripts/mcp_server/metadata.ts +83 -0
- package/src/scripts/mcp_server/prompts.ts +711 -0
- package/src/scripts/mcp_server/resources.ts +343 -0
- package/src/scripts/mcp_server/server.ts +439 -0
- package/src/scripts/mcp_server/telemetry.ts +154 -0
- package/src/scripts/mcp_server/tools.ts +1031 -0
- package/src/scripts/mcp_setup.sh +25 -52
- package/src/scripts/mcp_telemetry_health.ts +362 -0
- package/src/scripts/mcp_telemetry_query.ts +371 -0
- package/src/scripts/mcp_telemetry_store.ts +422 -0
- package/src/scripts/measure_augment_budget.ts +453 -0
- package/src/scripts/measure_density.ts +618 -0
- package/src/scripts/measure_frugality_savings.ts +353 -0
- package/src/scripts/measure_markitdown_lift.ts +299 -0
- package/src/scripts/measure_patterns.ts +682 -0
- package/src/scripts/measure_projection_bytes.ts +425 -0
- package/src/scripts/measure_rule_budget.ts +627 -0
- package/src/scripts/measure_skill_reduction.ts +442 -0
- package/src/scripts/media/lib/adapter-common.sh +247 -0
- package/src/scripts/media/lib/adapter-contract.md +329 -0
- package/src/scripts/media/lib/fixtures/comfyui/result.json +1 -0
- package/src/scripts/media/lib/fixtures/fal/result.json +1 -0
- package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/flux/result.json +1 -0
- package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/gemini-image/result.json +1 -0
- package/src/scripts/media/lib/fixtures/gemini-veo/result.json +1 -0
- package/src/scripts/media/lib/fixtures/higgsfield/result.json +1 -0
- package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
- package/src/scripts/media/lib/fixtures/ideogram/result.json +1 -0
- package/src/scripts/media/lib/fixtures/kling/result.json +1 -0
- package/src/scripts/media/lib/fixtures/musetalk/result.json +1 -0
- package/src/scripts/media/lib/fixtures/openai-images/result.json +1 -0
- package/src/scripts/media/lib/fixtures/recraft/asset-0001.svg +1 -0
- package/src/scripts/media/lib/fixtures/recraft/result.json +1 -0
- package/src/scripts/media/lib/fixtures/replicate/result.json +1 -0
- package/src/scripts/media/lib/fixtures/sora/result.json +1 -0
- package/src/scripts/media/lib/fixtures/syncso/result.json +1 -0
- package/src/scripts/media/lib/load-config.sh +180 -0
- package/src/scripts/media/lib/redact.sh +85 -0
- package/src/scripts/memory_hash.ts +331 -0
- package/src/scripts/memory_lookup.ts +1278 -0
- package/src/scripts/memory_report.ts +845 -0
- package/src/scripts/memory_signal.ts +417 -0
- package/src/scripts/memory_status.ts +189 -0
- package/src/scripts/migrate_command_suggestions.ts +341 -0
- package/src/scripts/migrate_frontmatter_defaults.ts +539 -0
- package/src/scripts/migration_status.ts +301 -0
- package/src/scripts/mine_session.ts +645 -0
- package/src/scripts/minimal_safe_diff_hook.ts +355 -0
- package/src/scripts/move_artefact.ts +869 -0
- package/src/scripts/new_skill.ts +404 -0
- package/src/scripts/onboarding_gate_hook.ts +224 -0
- package/src/scripts/pack_dependency_allowlist.json +2 -2
- package/src/scripts/pack_mcp_content.ts +552 -0
- package/src/scripts/parity/README.md +140 -0
- package/src/scripts/parity/compare.ts +189 -0
- package/src/scripts/parity/coverage_diff.ts +199 -0
- package/src/scripts/parity/phase-manifest.json +93 -0
- package/src/scripts/parity/phase_gate.ts +270 -0
- package/src/scripts/parity/replay.ts +320 -0
- package/src/scripts/pattern_share.ts +363 -0
- package/src/scripts/plan_physical_move.ts +605 -0
- package/src/scripts/prediction-pool/poisson_sim.ts +537 -0
- package/src/scripts/prediction-pool/pool_winsim.ts +677 -0
- package/src/scripts/prediction-pool/score_ev.ts +546 -0
- package/src/scripts/print_required_checks.ts +249 -0
- package/src/scripts/probe_projection_fidelity.ts +468 -0
- package/src/scripts/probe_skill_registration.ts +787 -0
- package/src/scripts/profile_staleness_hook.ts +169 -0
- package/src/scripts/profile_use.ts +227 -0
- package/src/scripts/project_thin_rules.ts +387 -0
- package/src/scripts/propose_modules_config.ts +311 -0
- package/src/scripts/prototype_lint_contradictions.ts +414 -0
- package/src/scripts/prove_pack_extractable.ts +388 -0
- package/src/scripts/readme_linter.ts +913 -0
- package/src/scripts/redact_hook_capture.ts +325 -0
- package/src/scripts/refine_ticket_detect.ts +703 -0
- package/src/scripts/release.ts +1697 -0
- package/src/scripts/render_benchmark_md.ts +664 -0
- package/src/scripts/render_value_md.ts +506 -0
- package/src/scripts/repro/repro_marketplace_install_gap.sh +1 -1
- package/src/scripts/roadmap_progress_hook.ts +410 -0
- package/src/scripts/router_telemetry.ts +972 -0
- package/src/scripts/run.ts +98 -0
- package/src/scripts/run_skill_evals.ts +477 -0
- package/src/scripts/runtime_dispatcher.ts +586 -0
- package/src/scripts/runtime_handler.ts +231 -0
- package/src/scripts/runtime_registry.ts +394 -0
- package/src/scripts/schemas/command.schema.json +7 -1
- package/src/scripts/schemas/mission-catalog.schema.json +112 -0
- package/src/scripts/schemas/mission.schema.json +87 -0
- package/src/scripts/schemas/pack.schema.json +6 -0
- package/src/scripts/schemas/rule.schema.json +1 -0
- package/src/scripts/schemas/skill.schema.json +1 -0
- package/src/scripts/schemas/ticket-manifest.schema.json +35 -0
- package/src/scripts/schemas/ticket.schema.json +60 -0
- package/src/scripts/score_skill_selection.ts +570 -0
- package/src/scripts/security_audit_config.ts +423 -0
- package/src/scripts/skill_collision_clusters.ts +448 -0
- package/src/scripts/skill_discovery.ts +690 -0
- package/src/scripts/skill_linter.ts +4276 -0
- package/src/scripts/skill_overlap.ts +414 -0
- package/src/scripts/skill_preview.ts +548 -0
- package/src/scripts/skill_tools/audit_persona_coverage.ts +427 -0
- package/src/scripts/skill_tools/audit_user_type_coverage.ts +507 -0
- package/src/scripts/skill_tools/index.ts +28 -0
- package/src/scripts/skill_tools/run_block_d_eval.ts +373 -0
- package/src/scripts/skill_tools/score_skill_relevance.ts +475 -0
- package/src/scripts/skill_tools/suggest_skill_for_task.ts +288 -0
- package/src/scripts/skill_trigger_eval.ts +1046 -0
- package/src/scripts/skill_usage_collect.ts +465 -0
- package/src/scripts/skill_usage_report.ts +364 -0
- package/src/scripts/smoke/kernel.sh +4 -5
- package/src/scripts/smoke/router.sh +76 -76
- package/src/scripts/smoke/schema.sh +2 -2
- package/src/scripts/smoke/skills.sh +73 -52
- package/src/scripts/smoke_path_resolution.ts +194 -0
- package/src/scripts/smoke_quickstart.ts +224 -0
- package/src/scripts/snapshot_agent_outputs.ts +375 -0
- package/src/scripts/spotcheck_thin_root.ts +247 -0
- package/src/scripts/surface-tiers.yml +68 -0
- package/src/scripts/sync_agent_settings.ts +763 -0
- package/src/scripts/sync_github_metadata.ts +550 -0
- package/src/scripts/sync_gitignore.ts +630 -0
- package/src/scripts/sync_yaml_rt.ts +910 -0
- package/src/scripts/telegraph_stats.ts +447 -0
- package/src/scripts/tool_registry.ts +330 -0
- package/src/scripts/tools/adapter_errors.ts +93 -0
- package/src/scripts/tools/base_adapter.ts +147 -0
- package/src/scripts/tools/github_adapter.ts +229 -0
- package/src/scripts/tools/jira_adapter.ts +196 -0
- package/src/scripts/trigger_coverage.ts +251 -0
- package/src/scripts/update_counts.ts +284 -0
- package/src/scripts/update_prices.ts +219 -0
- package/src/scripts/validate_agent_settings.ts +265 -0
- package/src/scripts/validate_decision_engine.ts +366 -0
- package/src/scripts/validate_discovery_manifest.ts +160 -0
- package/src/scripts/validate_frontmatter.ts +1030 -0
- package/src/scripts/validate_pack_yaml.ts +0 -0
- package/src/scripts/validate_safe_paths.ts +164 -0
- package/src/scripts/validate_telegraph_carveouts.ts +485 -0
- package/src/scripts/verify_before_complete_hook.ts +306 -0
- package/src/scripts/verify_physical_move.ts +411 -0
- package/src/scripts/wrapper_freshness_hook.ts +179 -0
- package/dist/agent-src/commands/chat-history/learn.md +0 -184
- package/dist/agent-src/commands/chat-history/show.md +0 -113
- package/dist/agent-src/commands/fix/pr-bot-comments.md +0 -157
- package/dist/agent-src/commands/fix/pr-developer-comments.md +0 -163
- package/dist/agent-src/scripts/update_roadmap_progress.py +0 -537
- package/dist/agent-src/skills/corpus-grounding/scripts/bm25_search.py +0 -212
- package/dist/agent-src/skills/corpus-grounding/scripts/decision_engine.py +0 -438
- package/dist/agent-src/skills/corpus-grounding/scripts/ground.py +0 -166
- package/dist/agent-src/skills/corpus-grounding/scripts/schema_validator.py +0 -160
- package/dist/agent-src/skills/design-tokens/scripts/tokens.py +0 -296
- package/dist/agent-src/skills/react-shadcn-ui/scripts/shadcn_add.py +0 -299
- package/dist/agent-src/skills/tailwind-engineer/scripts/tailwind_config_gen.py +0 -463
- package/dist/agent-src/templates/agents/memory/architecture-decisions.example.yml +0 -95
- package/dist/agent-src/templates/scripts/check_memory.py +0 -283
- package/dist/agent-src/templates/scripts/check_memory_proposal.py +0 -180
- package/dist/agent-src/templates/scripts/implement_ticket/__init__.py +0 -94
- package/dist/agent-src/templates/scripts/implement_ticket/__main__.py +0 -15
- package/dist/agent-src/templates/scripts/memory_hash.py +0 -75
- package/dist/agent-src/templates/scripts/memory_lookup.py +0 -577
- package/dist/agent-src/templates/scripts/memory_report.py +0 -184
- package/dist/agent-src/templates/scripts/memory_signal.py +0 -167
- package/dist/agent-src/templates/scripts/memory_status.py +0 -257
- package/dist/agent-src/templates/scripts/pr_review_routing.py +0 -340
- package/dist/agent-src/templates/scripts/pr_risk_review.py +0 -211
- package/dist/agent-src/templates/scripts/telemetry/__init__.py +0 -42
- package/dist/agent-src/templates/scripts/telemetry/aggregator.py +0 -169
- package/dist/agent-src/templates/scripts/telemetry/boundary.py +0 -171
- package/dist/agent-src/templates/scripts/telemetry/engagement.py +0 -297
- package/dist/agent-src/templates/scripts/telemetry/report_renderer.py +0 -197
- package/dist/agent-src/templates/scripts/telemetry/settings.py +0 -177
- package/dist/agent-src/templates/scripts/telemetry_record.py +0 -179
- package/dist/agent-src/templates/scripts/telemetry_report.py +0 -161
- package/dist/agent-src/templates/scripts/telemetry_status.py +0 -142
- package/dist/agent-src/templates/scripts/tier_usage_report.py +0 -183
- package/dist/agent-src/templates/scripts/work_engine/__init__.py +0 -58
- package/dist/agent-src/templates/scripts/work_engine/__main__.py +0 -9
- package/dist/agent-src/templates/scripts/work_engine/_lib/__init__.py +0 -7
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.py +0 -840
- package/dist/agent-src/templates/scripts/work_engine/_lib/user_global_paths.py +0 -249
- package/dist/agent-src/templates/scripts/work_engine/cli.py +0 -195
- package/dist/agent-src/templates/scripts/work_engine/cli_args.py +0 -116
- package/dist/agent-src/templates/scripts/work_engine/delivery_state.py +0 -137
- package/dist/agent-src/templates/scripts/work_engine/directives/__init__.py +0 -33
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/__init__.py +0 -98
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/analyze.py +0 -98
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.py +0 -145
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/memory.py +0 -136
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/plan.py +0 -175
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/refine.py +0 -396
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/report.py +0 -227
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.py +0 -180
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.py +0 -170
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/__init__.py +0 -116
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/contract.py +0 -254
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.py +0 -229
- package/dist/agent-src/templates/scripts/work_engine/directives/mixed/ui.py +0 -231
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/__init__.py +0 -113
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/_passthrough.py +0 -44
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.py +0 -241
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.py +0 -414
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.py +0 -335
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.py +0 -513
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.py +0 -471
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/__init__.py +0 -119
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.py +0 -37
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.py +0 -165
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.py +0 -66
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/report.py +0 -62
- package/dist/agent-src/templates/scripts/work_engine/directives/ui_trivial/test.py +0 -115
- package/dist/agent-src/templates/scripts/work_engine/dispatcher.py +0 -331
- package/dist/agent-src/templates/scripts/work_engine/emitters.py +0 -68
- package/dist/agent-src/templates/scripts/work_engine/errors.py +0 -19
- package/dist/agent-src/templates/scripts/work_engine/hook_bootstrap.py +0 -91
- package/dist/agent-src/templates/scripts/work_engine/hooks/__init__.py +0 -54
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +0 -35
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.py +0 -59
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.py +0 -43
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.py +0 -41
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.py +0 -162
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.py +0 -163
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.py +0 -53
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.py +0 -50
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.py +0 -141
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.py +0 -52
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/trace.py +0 -84
- package/dist/agent-src/templates/scripts/work_engine/hooks/context.py +0 -66
- package/dist/agent-src/templates/scripts/work_engine/hooks/events.py +0 -44
- package/dist/agent-src/templates/scripts/work_engine/hooks/exceptions.py +0 -79
- package/dist/agent-src/templates/scripts/work_engine/hooks/registry.py +0 -60
- package/dist/agent-src/templates/scripts/work_engine/hooks/runner.py +0 -73
- package/dist/agent-src/templates/scripts/work_engine/hooks/settings.py +0 -196
- package/dist/agent-src/templates/scripts/work_engine/input_builders.py +0 -163
- package/dist/agent-src/templates/scripts/work_engine/intent/__init__.py +0 -47
- package/dist/agent-src/templates/scripts/work_engine/intent/classify.py +0 -280
- package/dist/agent-src/templates/scripts/work_engine/migration/__init__.py +0 -8
- package/dist/agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +0 -231
- package/dist/agent-src/templates/scripts/work_engine/orchestration.py +0 -193
- package/dist/agent-src/templates/scripts/work_engine/persona_policy.py +0 -85
- package/dist/agent-src/templates/scripts/work_engine/resolvers/__init__.py +0 -22
- package/dist/agent-src/templates/scripts/work_engine/resolvers/diff.py +0 -106
- package/dist/agent-src/templates/scripts/work_engine/resolvers/file.py +0 -113
- package/dist/agent-src/templates/scripts/work_engine/resolvers/prompt.py +0 -90
- package/dist/agent-src/templates/scripts/work_engine/scoring/__init__.py +0 -14
- package/dist/agent-src/templates/scripts/work_engine/scoring/confidence.py +0 -300
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.py +0 -351
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_trace.py +0 -141
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.py +0 -284
- package/dist/agent-src/templates/scripts/work_engine/stack/__init__.py +0 -31
- package/dist/agent-src/templates/scripts/work_engine/stack/detect.py +0 -187
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.py +0 -481
- package/dist/agent-src/templates/scripts/work_engine/state.py +0 -694
- package/dist/agent-src/templates/scripts/work_engine/state_io.py +0 -202
- package/dist/cli/python/resolvePython.js +0 -38
- package/dist/cli/python/resolvePython.js.map +0 -1
- package/docs/case-studies/frontend-design-vs-ui-ux-pro-max.md +0 -86
- package/docs/contracts/agent-memory-contract.md +0 -159
- package/docs/parity/bench-ruflo.json +0 -58
- package/docs/parity/ruflo.md +0 -46
- package/src/scripts/__pycache__/validate_frontmatter.cpython-312.pyc +0 -0
- package/src/scripts/_archive/_backfill_skill_domains.py +0 -140
- package/src/scripts/_archive/_bootstrap_tier_frontmatter.py +0 -151
- package/src/scripts/_archive/_p43_bodies.py +0 -235
- package/src/scripts/_archive/_p43_condense.py +0 -118
- package/src/scripts/_archive/_p4_migrate.py +0 -199
- package/src/scripts/_archive/_phase2_shim_helper.py +0 -109
- package/src/scripts/_archive/_pilot_council_question.py +0 -57
- package/src/scripts/_cli/__init__.py +0 -0
- package/src/scripts/_cli/cmd_doctor.py +0 -1583
- package/src/scripts/_cli/cmd_explain.py +0 -355
- package/src/scripts/_cli/cmd_export.py +0 -157
- package/src/scripts/_cli/cmd_migrate.py +0 -524
- package/src/scripts/_cli/cmd_prune.py +0 -322
- package/src/scripts/_cli/cmd_refresh.py +0 -179
- package/src/scripts/_cli/cmd_settings_check.py +0 -171
- package/src/scripts/_cli/cmd_settings_migrate.py +0 -147
- package/src/scripts/_cli/cmd_sync.py +0 -166
- package/src/scripts/_cli/cmd_uninstall.py +0 -476
- package/src/scripts/_cli/cmd_update.py +0 -279
- package/src/scripts/_cli/cmd_upgrade.py +0 -172
- package/src/scripts/_cli/cmd_validate.py +0 -177
- package/src/scripts/_cli/cmd_versions.py +0 -160
- package/src/scripts/_cli/explain_last/__init__.py +0 -122
- package/src/scripts/_cli/explain_last/assumptions.py +0 -59
- package/src/scripts/_cli/explain_last/council.py +0 -105
- package/src/scripts/_cli/explain_last/halt.py +0 -44
- package/src/scripts/_cli/explain_last/inputs.py +0 -128
- package/src/scripts/_cli/explain_last/memory.py +0 -94
- package/src/scripts/_cli/explain_last/provider.py +0 -52
- package/src/scripts/_cli/explain_last/render.py +0 -52
- package/src/scripts/_cli/explain_last/route.py +0 -59
- package/src/scripts/_cli/explain_last/scrubber.py +0 -105
- package/src/scripts/_cli/explain_last/sections/__init__.py +0 -35
- package/src/scripts/_cli/explain_last/sections/assumptions.py +0 -21
- package/src/scripts/_cli/explain_last/sections/council.py +0 -27
- package/src/scripts/_cli/explain_last/sections/halt.py +0 -31
- package/src/scripts/_cli/explain_last/sections/header.py +0 -24
- package/src/scripts/_cli/explain_last/sections/inputs.py +0 -27
- package/src/scripts/_cli/explain_last/sections/memory.py +0 -21
- package/src/scripts/_cli/explain_last/sections/pack.py +0 -16
- package/src/scripts/_cli/explain_last/sections/provider.py +0 -26
- package/src/scripts/_cli/explain_last/sections/route.py +0 -22
- package/src/scripts/_cli/explain_last/state_loader.py +0 -76
- package/src/scripts/_emit_domain_table.py +0 -35
- package/src/scripts/_lib/__init__.py +0 -5
- package/src/scripts/_lib/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/scripts/_lib/__pycache__/agent_src.cpython-312.pyc +0 -0
- package/src/scripts/_lib/agent_settings.py +0 -840
- package/src/scripts/_lib/agent_src.py +0 -491
- package/src/scripts/_lib/agents_overlay.py +0 -120
- package/src/scripts/_lib/bench_ab_cache.py +0 -162
- package/src/scripts/_lib/bench_ab_scoring.py +0 -209
- package/src/scripts/_lib/bench_cost.py +0 -138
- package/src/scripts/_lib/bench_quality.py +0 -118
- package/src/scripts/_lib/bench_report.py +0 -149
- package/src/scripts/_lib/bench_telegraph.py +0 -273
- package/src/scripts/_lib/bench_telegraph_report.py +0 -151
- package/src/scripts/_lib/changelog_eras.py +0 -330
- package/src/scripts/_lib/claude_desktop_bundler.py +0 -238
- package/src/scripts/_lib/cli_wrapper.py +0 -64
- package/src/scripts/_lib/fs_atomic.py +0 -116
- package/src/scripts/_lib/global_deploy_inventory.py +0 -282
- package/src/scripts/_lib/install_regenerator.py +0 -134
- package/src/scripts/_lib/installed_lock.py +0 -256
- package/src/scripts/_lib/installed_tools.py +0 -381
- package/src/scripts/_lib/json_pointers.py +0 -260
- package/src/scripts/_lib/linked_projects.py +0 -238
- package/src/scripts/_lib/model_tier.py +0 -52
- package/src/scripts/_lib/module_detection.py +0 -223
- package/src/scripts/_lib/pin_resolver.py +0 -152
- package/src/scripts/_lib/script_output.py +0 -144
- package/src/scripts/_lib/token_count.py +0 -95
- package/src/scripts/_lib/update_check.py +0 -207
- package/src/scripts/_lib/user_global_paths.py +0 -249
- package/src/scripts/_lib/value_ladder.py +0 -696
- package/src/scripts/_lib/value_report.py +0 -455
- package/src/scripts/_phase4_bucket.py +0 -210
- package/src/scripts/_pilot_measure.py +0 -53
- package/src/scripts/_tmp_scan_framework_leakage.py +0 -119
- package/src/scripts/adoption_report.py +0 -195
- package/src/scripts/adoption_snapshot.py +0 -219
- package/src/scripts/adoption_status.py +0 -166
- package/src/scripts/adr/regenerate_index.py +0 -79
- package/src/scripts/ai-video/lib/adapter-common.sh +0 -231
- package/src/scripts/ai-video/lib/adapter-contract.md +0 -329
- package/src/scripts/ai-video/lib/fixtures/comfyui/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/fal/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/gemini-veo/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/higgsfield/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/kling/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/musetalk/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/openai-images/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/replicate/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/sora/result.json +0 -1
- package/src/scripts/ai-video/lib/fixtures/syncso/result.json +0 -1
- package/src/scripts/ai-video/lib/load-config.sh +0 -180
- package/src/scripts/ai-video/lib/redact.sh +0 -85
- package/src/scripts/ai_council/__init__.py +0 -40
- package/src/scripts/ai_council/_default_prices.py +0 -50
- package/src/scripts/ai_council/advisors.py +0 -148
- package/src/scripts/ai_council/airgap.py +0 -165
- package/src/scripts/ai_council/budget_guard.py +0 -202
- package/src/scripts/ai_council/bundler.py +0 -263
- package/src/scripts/ai_council/cli_hints.py +0 -123
- package/src/scripts/ai_council/clients.py +0 -1385
- package/src/scripts/ai_council/compile_corpus.py +0 -179
- package/src/scripts/ai_council/confidence_gate.py +0 -156
- package/src/scripts/ai_council/config.py +0 -1364
- package/src/scripts/ai_council/consensus.py +0 -329
- package/src/scripts/ai_council/events_log.py +0 -141
- package/src/scripts/ai_council/learn_low_impact_preview.py +0 -252
- package/src/scripts/ai_council/low_impact.py +0 -714
- package/src/scripts/ai_council/low_impact_corpus.py +0 -466
- package/src/scripts/ai_council/low_impact_intake.py +0 -163
- package/src/scripts/ai_council/modes.py +0 -131
- package/src/scripts/ai_council/necessity.py +0 -782
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_2a4_acceptance.py +0 -208
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_add_quiet.py +0 -149
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_budget_v2_audit.py +0 -206
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_estimate.py +0 -67
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_context_layer_v1_review.py +0 -292
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_followups_review.py +0 -259
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_inject_quiet_flag.py +0 -33
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_measure_v2.sh +0 -36
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_measure_verbosity.sh +0 -26
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_nondestructive_inline_audit.py +0 -209
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_per_task.sh +0 -41
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_phase4_dispatch_latency.py +0 -108
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_phase6_trigger_jaccard.py +0 -92
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_budget_rebalance.py +0 -257
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_phase_2a_post_revert.py +0 -197
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_rebalancing_audit.py +0 -149
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_roundtrip.py +0 -111
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_rule_hardening_v1.py +0 -251
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_silent_taskfiles.py +0 -98
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_open_questions.py +0 -232
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_optimization.py +0 -144
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_gaps.py +0 -252
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_structural_v3_review.py +0 -240
- package/src/scripts/ai_council/one_off_archive/2026-05/_one_off_tier_retrofit.py +0 -180
- package/src/scripts/ai_council/orchestrator.py +0 -1206
- package/src/scripts/ai_council/pricing.py +0 -215
- package/src/scripts/ai_council/probation_gate.py +0 -152
- package/src/scripts/ai_council/project_context.py +0 -159
- package/src/scripts/ai_council/prompts.py +0 -567
- package/src/scripts/ai_council/redact_low_impact_entry.py +0 -155
- package/src/scripts/ai_council/replay.py +0 -155
- package/src/scripts/ai_council/session.py +0 -366
- package/src/scripts/ai_council/shadow_dispatch.py +0 -235
- package/src/scripts/ai_council/solo_dispatch.py +0 -226
- package/src/scripts/annotate_discovery.py +0 -149
- package/src/scripts/apply_modules_config.py +0 -290
- package/src/scripts/audit_adr_coverage.py +0 -175
- package/src/scripts/audit_auto_rules.py +0 -175
- package/src/scripts/audit_cloud_compatibility.py +0 -362
- package/src/scripts/audit_command_surface.py +0 -669
- package/src/scripts/audit_initial_context.py +0 -237
- package/src/scripts/audit_likelihood.py +0 -148
- package/src/scripts/audit_mcp_tools.py +0 -146
- package/src/scripts/audit_overlap.py +0 -145
- package/src/scripts/audit_skill_descriptions.py +0 -180
- package/src/scripts/audit_skill_overlap.py +0 -207
- package/src/scripts/audit_user_type_axis.py +0 -140
- package/src/scripts/backfill_model_tier.py +0 -184
- package/src/scripts/bench_ab_cache_dispatch.py +0 -68
- package/src/scripts/bench_ab_clone.py +0 -170
- package/src/scripts/bench_ab_diff.py +0 -220
- package/src/scripts/bench_ab_integrity.py +0 -143
- package/src/scripts/bench_ab_run.py +0 -235
- package/src/scripts/bench_ab_task_runner.py +0 -369
- package/src/scripts/bench_ab_tracka_run.py +0 -202
- package/src/scripts/bench_baseline_ready.py +0 -108
- package/src/scripts/bench_condense_memory.py +0 -168
- package/src/scripts/bench_drift_check.py +0 -151
- package/src/scripts/bench_per_tool.py +0 -216
- package/src/scripts/bench_rtk_savings.py +0 -320
- package/src/scripts/bench_run.py +0 -272
- package/src/scripts/bench_runner.py +0 -158
- package/src/scripts/build_cloud_bundle.py +0 -458
- package/src/scripts/build_discovery_manifest.py +0 -747
- package/src/scripts/build_linear_digest.py +0 -260
- package/src/scripts/build_mcp_registry_manifest.py +0 -181
- package/src/scripts/build_rule_trigger_matrix.py +0 -350
- package/src/scripts/capture_showcase_session.py +0 -361
- package/src/scripts/chat_history.py +0 -1799
- package/src/scripts/check_always_budget.py +0 -532
- package/src/scripts/check_artefact_checksums.py +0 -111
- package/src/scripts/check_augment_description_cap.py +0 -79
- package/src/scripts/check_augmentignore.py +0 -72
- package/src/scripts/check_beta_review_markers.py +0 -127
- package/src/scripts/check_bite_sized_granularity.py +0 -99
- package/src/scripts/check_cluster_patterns.py +0 -206
- package/src/scripts/check_command_count_messaging.py +0 -152
- package/src/scripts/check_condensation.py +0 -375
- package/src/scripts/check_condensed_paths.py +0 -231
- package/src/scripts/check_context_paths.py +0 -202
- package/src/scripts/check_council_layout.py +0 -125
- package/src/scripts/check_council_references.py +0 -228
- package/src/scripts/check_discovery_determinism.py +0 -70
- package/src/scripts/check_gate_paths.py +0 -128
- package/src/scripts/check_iron_law_prominence.py +0 -145
- package/src/scripts/check_kernel_rule_bundle.py +0 -151
- package/src/scripts/check_md_language.py +0 -161
- package/src/scripts/check_memory.py +0 -443
- package/src/scripts/check_memory_proposal.py +0 -182
- package/src/scripts/check_module_management_neutral.py +0 -147
- package/src/scripts/check_no_local_settings_committed.py +0 -51
- package/src/scripts/check_no_new_legacy_path.py +0 -100
- package/src/scripts/check_no_roadmap_refs.py +0 -155
- package/src/scripts/check_one_off_location.py +0 -81
- package/src/scripts/check_overlay_cascade_subdirs.py +0 -129
- package/src/scripts/check_portability.py +0 -574
- package/src/scripts/check_proposal.py +0 -269
- package/src/scripts/check_public_catalog_links.py +0 -125
- package/src/scripts/check_public_links.py +0 -185
- package/src/scripts/check_references.py +0 -557
- package/src/scripts/check_release_includes_discovery.py +0 -61
- package/src/scripts/check_release_pr_shape.py +0 -123
- package/src/scripts/check_release_published.py +0 -145
- package/src/scripts/check_release_trunk_sync.py +0 -152
- package/src/scripts/check_reply_consistency.py +0 -169
- package/src/scripts/check_roadmap_trackable.py +0 -114
- package/src/scripts/check_role_doc_links.py +0 -110
- package/src/scripts/check_safety_floor_untouched.py +0 -125
- package/src/scripts/check_skill_requires.py +0 -147
- package/src/scripts/check_template_pin_drift.py +0 -129
- package/src/scripts/check_test_coverage_diff.py +0 -180
- package/src/scripts/check_token_optimizer_freshness.py +0 -146
- package/src/scripts/check_update_banner.py +0 -86
- package/src/scripts/ci_status.py +0 -301
- package/src/scripts/ci_summary.py +0 -131
- package/src/scripts/ci_time_ratio.py +0 -168
- package/src/scripts/command_suggester/__init__.py +0 -51
- package/src/scripts/command_suggester/cooldown.py +0 -132
- package/src/scripts/command_suggester/loader.py +0 -73
- package/src/scripts/command_suggester/match.py +0 -180
- package/src/scripts/command_suggester/rank.py +0 -120
- package/src/scripts/command_suggester/render.py +0 -86
- package/src/scripts/command_suggester/sanitize.py +0 -113
- package/src/scripts/command_suggester/settings.py +0 -127
- package/src/scripts/command_suggester/types.py +0 -78
- package/src/scripts/compile_router.py +0 -232
- package/src/scripts/condense.py +0 -1919
- package/src/scripts/condense_memory.py +0 -178
- package/src/scripts/config/__init__.py +0 -9
- package/src/scripts/config/packs.py +0 -157
- package/src/scripts/config/presets.py +0 -224
- package/src/scripts/config/profile_explain.py +0 -89
- package/src/scripts/config/profiles.py +0 -191
- package/src/scripts/config/session_profiles.py +0 -542
- package/src/scripts/context_hygiene_hook.py +0 -181
- package/src/scripts/cost_by_conversation.py +0 -78
- package/src/scripts/cost_summary.py +0 -97
- package/src/scripts/council_cli.py +0 -2557
- package/src/scripts/council_prune.py +0 -81
- package/src/scripts/cross_repo_retrieve.py +0 -172
- package/src/scripts/discovery_stats.py +0 -70
- package/src/scripts/extract_audit_patterns.py +0 -202
- package/src/scripts/first_run_gate_hook.py +0 -179
- package/src/scripts/gen_discovery_baseline.py +0 -127
- package/src/scripts/generate_catalog.py +0 -116
- package/src/scripts/generate_command_flows.py +0 -191
- package/src/scripts/generate_index.py +0 -303
- package/src/scripts/generate_ownership_matrix.py +0 -378
- package/src/scripts/generate_pack_manifests.py +0 -340
- package/src/scripts/hooks/__init__.py +0 -1
- package/src/scripts/hooks/dispatch_hook.py +0 -461
- package/src/scripts/hooks/dispatch_issues.py +0 -136
- package/src/scripts/hooks/envelope.py +0 -98
- package/src/scripts/hooks/replay_hook.py +0 -144
- package/src/scripts/hooks/state_io.py +0 -145
- package/src/scripts/hooks_doctor.py +0 -223
- package/src/scripts/hooks_status.py +0 -157
- package/src/scripts/install.py +0 -5183
- package/src/scripts/inventory_abstraction_budget.py +0 -622
- package/src/scripts/inventory_frontmatter.py +0 -164
- package/src/scripts/inventory_meta_layers.py +0 -288
- package/src/scripts/iron_law_sha.py +0 -107
- package/src/scripts/linked_projects_list.py +0 -91
- package/src/scripts/lint_agent_skill_names.py +0 -150
- package/src/scripts/lint_agents_layout.py +0 -197
- package/src/scripts/lint_agents_md.py +0 -210
- package/src/scripts/lint_archived_skills.py +0 -159
- package/src/scripts/lint_artefact_frontmatter.py +0 -188
- package/src/scripts/lint_bench_ab.py +0 -172
- package/src/scripts/lint_bench_corpus.py +0 -255
- package/src/scripts/lint_command_flow_coverage.py +0 -132
- package/src/scripts/lint_command_routing.py +0 -160
- package/src/scripts/lint_command_tiers.py +0 -175
- package/src/scripts/lint_command_verbs.py +0 -206
- package/src/scripts/lint_commit_subjects.py +0 -139
- package/src/scripts/lint_context_spine_usage.py +0 -137
- package/src/scripts/lint_discovery_manifest.py +0 -176
- package/src/scripts/lint_discovery_vocabulary.py +0 -220
- package/src/scripts/lint_examples.py +0 -102
- package/src/scripts/lint_explain_trace.py +0 -80
- package/src/scripts/lint_featured_skills.py +0 -144
- package/src/scripts/lint_flows.py +0 -215
- package/src/scripts/lint_framework_leakage.py +0 -375
- package/src/scripts/lint_frontmatter_boilerplate.py +0 -77
- package/src/scripts/lint_ghostwriter_source.py +0 -242
- package/src/scripts/lint_global_paths.py +0 -148
- package/src/scripts/lint_handoffs.py +0 -217
- package/src/scripts/lint_hook_concern_budget.py +0 -207
- package/src/scripts/lint_hook_manifest.py +0 -217
- package/src/scripts/lint_load_context.py +0 -196
- package/src/scripts/lint_marketplace.py +0 -180
- package/src/scripts/lint_marketplace_install_completeness.py +0 -198
- package/src/scripts/lint_mcp_registry_manifest.py +0 -69
- package/src/scripts/lint_media_policy_linkage.py +0 -140
- package/src/scripts/lint_model_tier_coverage.py +0 -73
- package/src/scripts/lint_namespace.py +0 -135
- package/src/scripts/lint_namespace_collisions.py +0 -103
- package/src/scripts/lint_new_skill_gate.py +0 -144
- package/src/scripts/lint_no_new_atomic_commands.py +0 -180
- package/src/scripts/lint_one_off_age.py +0 -184
- package/src/scripts/lint_orchestration_dsl.py +0 -217
- package/src/scripts/lint_orchestrator_auto_detect.py +0 -111
- package/src/scripts/lint_pack_boundaries.py +0 -147
- package/src/scripts/lint_pack_dependencies.py +0 -137
- package/src/scripts/lint_pack_first_win.py +0 -121
- package/src/scripts/lint_persona_governance.py +0 -164
- package/src/scripts/lint_positioning.py +0 -143
- package/src/scripts/lint_profile_overlay_set_only.py +0 -179
- package/src/scripts/lint_readme_jargon.py +0 -131
- package/src/scripts/lint_readme_size.py +0 -33
- package/src/scripts/lint_regression.py +0 -251
- package/src/scripts/lint_roadmap_ci_steps.py +0 -186
- package/src/scripts/lint_roadmap_complexity.py +0 -220
- package/src/scripts/lint_role_experiences.py +0 -255
- package/src/scripts/lint_rule_interactions.py +0 -170
- package/src/scripts/lint_rule_tiers.py +0 -90
- package/src/scripts/lint_showcase_sessions.py +0 -148
- package/src/scripts/lint_skill_tools.py +0 -168
- package/src/scripts/lint_topics_yaml.py +0 -89
- package/src/scripts/lint_trust_coherence.py +0 -212
- package/src/scripts/lint_value_dashboard.py +0 -218
- package/src/scripts/mcp_parity_smoke.py +0 -316
- package/src/scripts/mcp_render.py +0 -173
- package/src/scripts/mcp_server/__init__.py +0 -19
- package/src/scripts/mcp_server/__main__.py +0 -12
- package/src/scripts/mcp_server/catalog.py +0 -125
- package/src/scripts/mcp_server/metadata.py +0 -75
- package/src/scripts/mcp_server/prompts.py +0 -442
- package/src/scripts/mcp_server/requirements.txt +0 -4
- package/src/scripts/mcp_server/resources.py +0 -201
- package/src/scripts/mcp_server/server.py +0 -270
- package/src/scripts/mcp_server/telemetry.py +0 -128
- package/src/scripts/mcp_server/tools.py +0 -950
- package/src/scripts/mcp_telemetry_health.py +0 -214
- package/src/scripts/mcp_telemetry_query.py +0 -203
- package/src/scripts/mcp_telemetry_store.py +0 -211
- package/src/scripts/measure_augment_budget.py +0 -214
- package/src/scripts/measure_density.py +0 -232
- package/src/scripts/measure_frugality_savings.py +0 -164
- package/src/scripts/measure_markitdown_lift.py +0 -127
- package/src/scripts/measure_patterns.py +0 -376
- package/src/scripts/measure_projection_bytes.py +0 -159
- package/src/scripts/measure_rule_budget.py +0 -347
- package/src/scripts/measure_skill_reduction.py +0 -102
- package/src/scripts/memory_hash.py +0 -75
- package/src/scripts/memory_lookup.py +0 -705
- package/src/scripts/memory_report.py +0 -336
- package/src/scripts/memory_signal.py +0 -212
- package/src/scripts/memory_status.py +0 -257
- package/src/scripts/migrate_command_suggestions.py +0 -151
- package/src/scripts/migrate_frontmatter_defaults.py +0 -245
- package/src/scripts/mine_session.py +0 -279
- package/src/scripts/minimal_safe_diff_hook.py +0 -245
- package/src/scripts/move_artefact.py +0 -143
- package/src/scripts/new_skill.py +0 -148
- package/src/scripts/onboarding_gate_hook.py +0 -142
- package/src/scripts/pack_mcp_content.py +0 -293
- package/src/scripts/plan_physical_move.py +0 -353
- package/src/scripts/prediction-pool/poisson_sim.py +0 -167
- package/src/scripts/prediction-pool/pool_winsim.py +0 -236
- package/src/scripts/prediction-pool/score_ev.py +0 -188
- package/src/scripts/print_required_checks.py +0 -196
- package/src/scripts/probe_projection_fidelity.py +0 -202
- package/src/scripts/probe_skill_registration.py +0 -413
- package/src/scripts/profile_staleness_hook.py +0 -69
- package/src/scripts/profile_use.py +0 -164
- package/src/scripts/project_thin_rules.py +0 -168
- package/src/scripts/propose_modules_config.py +0 -145
- package/src/scripts/prototype_lint_contradictions.py +0 -150
- package/src/scripts/prove_pack_extractable.py +0 -187
- package/src/scripts/readme_linter.py +0 -589
- package/src/scripts/redact_hook_capture.py +0 -148
- package/src/scripts/refine_ticket_detect.py +0 -646
- package/src/scripts/release.py +0 -1091
- package/src/scripts/render_benchmark_md.py +0 -312
- package/src/scripts/render_value_md.py +0 -347
- package/src/scripts/requirements-evals.txt +0 -8
- package/src/scripts/roadmap_progress_hook.py +0 -274
- package/src/scripts/router_telemetry.py +0 -470
- package/src/scripts/run_skill_evals.py +0 -185
- package/src/scripts/runtime_dispatcher.py +0 -276
- package/src/scripts/runtime_handler.py +0 -148
- package/src/scripts/runtime_registry.py +0 -166
- package/src/scripts/score_skill_selection.py +0 -198
- package/src/scripts/setup_eval_venv.sh +0 -58
- package/src/scripts/skill_collision_clusters.py +0 -162
- package/src/scripts/skill_discovery.py +0 -254
- package/src/scripts/skill_linter.py +0 -3694
- package/src/scripts/skill_overlap.py +0 -204
- package/src/scripts/skill_preview.py +0 -179
- package/src/scripts/skill_tools/__init__.py +0 -22
- package/src/scripts/skill_tools/audit_persona_coverage.py +0 -147
- package/src/scripts/skill_tools/audit_user_type_coverage.py +0 -148
- package/src/scripts/skill_tools/run_block_d_eval.py +0 -129
- package/src/scripts/skill_tools/score_skill_relevance.py +0 -169
- package/src/scripts/skill_tools/suggest_skill_for_task.py +0 -113
- package/src/scripts/skill_trigger_eval.py +0 -682
- package/src/scripts/skill_usage_collect.py +0 -191
- package/src/scripts/skill_usage_report.py +0 -162
- package/src/scripts/smoke_path_resolution.py +0 -93
- package/src/scripts/smoke_quickstart.py +0 -144
- package/src/scripts/snapshot_agent_outputs.py +0 -144
- package/src/scripts/spotcheck_thin_root.py +0 -134
- package/src/scripts/sync_agent_settings.py +0 -180
- package/src/scripts/sync_github_metadata.py +0 -147
- package/src/scripts/sync_gitignore.py +0 -291
- package/src/scripts/sync_yaml_rt.py +0 -734
- package/src/scripts/telegraph_stats.py +0 -119
- package/src/scripts/tool_registry.py +0 -146
- package/src/scripts/tools/__init__.py +0 -1
- package/src/scripts/tools/adapter_errors.py +0 -63
- package/src/scripts/tools/base_adapter.py +0 -91
- package/src/scripts/tools/github_adapter.py +0 -128
- package/src/scripts/tools/jira_adapter.py +0 -115
- package/src/scripts/trigger_coverage.py +0 -129
- package/src/scripts/update_counts.py +0 -199
- package/src/scripts/update_prices.py +0 -125
- package/src/scripts/validate_agent_settings.py +0 -124
- package/src/scripts/validate_decision_engine.py +0 -136
- package/src/scripts/validate_discovery_manifest.py +0 -94
- package/src/scripts/validate_frontmatter.py +0 -647
- package/src/scripts/validate_pack_yaml.py +0 -179
- package/src/scripts/validate_safe_paths.py +0 -118
- package/src/scripts/validate_telegraph_carveouts.py +0 -129
- package/src/scripts/verify_before_complete_hook.py +0 -216
- package/src/scripts/verify_physical_move.py +0 -185
- package/src/scripts/wrapper_freshness_hook.py +0 -86
- /package/dist/agent-src/skills/design-intelligence/data/{typography.csv → font-pairings-reference.csv} +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/allin1/analysis.json +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/comfyui/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/fal/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/gemini-veo/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/higgsfield/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/kling/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/musetalk/lipsync-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/openai-images/scene-0001.png +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/replicate/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/sora/scene-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/syncso/lipsync-0001.mp4 +0 -0
- /package/src/scripts/{ai-video → media}/lib/fixtures/whisperx/transcript.json +0 -0
- /package/src/scripts/{ai-video → media}/lib/telemetry.sh +0 -0
|
@@ -1,2557 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Council CLI — `./agent-config council:{estimate,run,render}`.
|
|
3
|
-
|
|
4
|
-
Wraps `scripts.ai_council.orchestrator` for non-interactive callers.
|
|
5
|
-
Subcommands:
|
|
6
|
-
|
|
7
|
-
estimate Bundle + estimate per-member cost (no API call, no spend).
|
|
8
|
-
run Same + estimate, then call the council. Requires --confirm.
|
|
9
|
-
render Re-render a saved responses JSON to the markdown report.
|
|
10
|
-
|
|
11
|
-
`./agent-config` is non-interactive by contract — the cost gate is an
|
|
12
|
-
explicit `--confirm` flag, never an interactive y/n.
|
|
13
|
-
"""
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import argparse
|
|
17
|
-
import json
|
|
18
|
-
import sys
|
|
19
|
-
from dataclasses import asdict
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
try: # invocation-agnostic import (repo-root-on-path vs scripts-on-path)
|
|
22
|
-
from scripts._lib.agent_settings import (
|
|
23
|
-
project_settings_path, resolve_project_root,
|
|
24
|
-
)
|
|
25
|
-
except ModuleNotFoundError: # pragma: no cover
|
|
26
|
-
from _lib.agent_settings import (
|
|
27
|
-
project_settings_path, resolve_project_root,
|
|
28
|
-
)
|
|
29
|
-
from typing import Any
|
|
30
|
-
|
|
31
|
-
import yaml
|
|
32
|
-
|
|
33
|
-
# `PACKAGE_ROOT` is where `scripts.ai_council.*` lives — fixed relative to
|
|
34
|
-
# this file, used only for the import path below. `REPO_ROOT` is the project
|
|
35
|
-
# the council operates on: when invoked via the global `agent-config`
|
|
36
|
-
# wrapper from a consumer project it is that project (anchor-walked from
|
|
37
|
-
# CWD, or pinned via AGENT_CONFIG_PROJECT_ROOT / --root), NOT the package
|
|
38
|
-
# install dir. Hardcoding the package dir here was the bug — settings and
|
|
39
|
-
# `.ai-council.yml` were then read from the package (which has neither), so
|
|
40
|
-
# `council:*` always refused with `ai_council.enabled is false`.
|
|
41
|
-
PACKAGE_ROOT = Path(__file__).resolve().parents[1]
|
|
42
|
-
REPO_ROOT, _ = resolve_project_root(None)
|
|
43
|
-
SETTINGS_FILE = project_settings_path(REPO_ROOT)
|
|
44
|
-
AI_COUNCIL_FILE = REPO_ROOT / "agents" / "settings" / ".ai-council.yml"
|
|
45
|
-
|
|
46
|
-
# Canonical output dirs per ai-council § "Output path convention".
|
|
47
|
-
# Enforced at write-time by `_validate_council_output_path` so shell-side
|
|
48
|
-
# `>` redirects and forgetful agents can't strand artefacts at agents/ root.
|
|
49
|
-
COUNCIL_CANONICAL_DIRS: dict[str, str] = {
|
|
50
|
-
"responses": "agents/runtime/council/responses",
|
|
51
|
-
"sessions": "agents/runtime/council/sessions",
|
|
52
|
-
"questions": "agents/runtime/council/questions",
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def _validate_council_output_path(
|
|
57
|
-
path_str: str, *, kind: str, subcommand: str,
|
|
58
|
-
) -> Path:
|
|
59
|
-
"""Reject non-canonical --output paths at write-time.
|
|
60
|
-
|
|
61
|
-
`kind` selects the expected canonical dir (`responses`, `sessions`,
|
|
62
|
-
`questions`). Raises `argparse.ArgumentTypeError` on violation so
|
|
63
|
-
`main()` surfaces a clean ❌ message and returns 2.
|
|
64
|
-
"""
|
|
65
|
-
expected_rel = COUNCIL_CANONICAL_DIRS[kind]
|
|
66
|
-
expected_abs = (REPO_ROOT / expected_rel).resolve()
|
|
67
|
-
p = Path(path_str)
|
|
68
|
-
target = p if p.is_absolute() else (REPO_ROOT / p)
|
|
69
|
-
target_resolved = target.resolve()
|
|
70
|
-
try:
|
|
71
|
-
target_resolved.relative_to(expected_abs)
|
|
72
|
-
except ValueError as exc:
|
|
73
|
-
raise argparse.ArgumentTypeError(
|
|
74
|
-
f"council:{subcommand} --output must live under "
|
|
75
|
-
f"{expected_rel}/ (per ai-council § Output path convention); "
|
|
76
|
-
f"got {path_str!r}."
|
|
77
|
-
) from exc
|
|
78
|
-
return p
|
|
79
|
-
|
|
80
|
-
sys.path.insert(0, str(PACKAGE_ROOT))
|
|
81
|
-
|
|
82
|
-
from scripts.ai_council.bundler import ( # noqa: E402
|
|
83
|
-
BundleTooLarge, bundle_prompt, bundle_roadmap,
|
|
84
|
-
)
|
|
85
|
-
from scripts.ai_council.clients import ( # noqa: E402
|
|
86
|
-
DEFAULT_MAX_TOKENS, UNLIMITED_TOKENS_FALLBACK,
|
|
87
|
-
AnthropicClient, AnthropicCliClient, CliClient, CliClientError,
|
|
88
|
-
CouncilResponse, ExternalAIClient, GeminiClient, GeminiCliClient,
|
|
89
|
-
ManualClient, OpenAIClient, OpenAICliClient, PerplexityClient,
|
|
90
|
-
PerplexityCliClient, XAIClient, XAICliClient,
|
|
91
|
-
load_anthropic_key, load_cli_call_counts, load_openai_key,
|
|
92
|
-
quota_summary_line, reset_cli_call_counts,
|
|
93
|
-
)
|
|
94
|
-
from scripts.ai_council.advisors import ( # noqa: E402
|
|
95
|
-
AdvisorPlan, build_persona_labels, plan_advisor_swap,
|
|
96
|
-
)
|
|
97
|
-
from scripts.ai_council.cli_hints import format_install_hints # noqa: E402
|
|
98
|
-
from scripts.ai_council.config import ( # noqa: E402
|
|
99
|
-
AdvisorConfig, CouncilConfig, CouncilConfigError,
|
|
100
|
-
load_council_config, resolve_api_key,
|
|
101
|
-
)
|
|
102
|
-
from scripts.ai_council.solo_dispatch import ( # noqa: E402
|
|
103
|
-
AuthCache, select_solo_member,
|
|
104
|
-
)
|
|
105
|
-
from scripts.ai_council.modes import ( # noqa: E402
|
|
106
|
-
InvalidModeError, resolve_mode,
|
|
107
|
-
)
|
|
108
|
-
from scripts.ai_council.events_log import append_event # noqa: E402
|
|
109
|
-
from scripts.ai_council.necessity import ( # noqa: E402
|
|
110
|
-
ClassificationResult, SizeFitVerdict, classify_necessity,
|
|
111
|
-
classify_size_fit, downgrade_message, educate_message,
|
|
112
|
-
)
|
|
113
|
-
from scripts.ai_council.orchestrator import ( # noqa: E402
|
|
114
|
-
ConsensusResult,
|
|
115
|
-
CostBudget, CouncilQuestion, DebateCapExceeded, DebateCheckpoint,
|
|
116
|
-
DebateCostEstimate,
|
|
117
|
-
PeerReviewResult, consult, estimate, estimate_debate_cost, render,
|
|
118
|
-
run_consensus_scoring, run_debate, run_peer_review,
|
|
119
|
-
)
|
|
120
|
-
from scripts.ai_council.pricing import ( # noqa: E402
|
|
121
|
-
PriceTable, estimate_cost, load_prices,
|
|
122
|
-
)
|
|
123
|
-
from scripts.ai_council.project_context import detect_project_context # noqa: E402
|
|
124
|
-
from scripts.ai_council.replay import ( # noqa: E402
|
|
125
|
-
DecisionReplayInputs, render_decision_replay,
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
SCHEMA_VERSION = 1
|
|
129
|
-
|
|
130
|
-
#: Provider names accepted under `mode=api`. Mirrors the routing table
|
|
131
|
-
#: in ``_construct_api_member``; both must stay in sync.
|
|
132
|
-
_API_PROVIDERS = frozenset({"anthropic", "openai", "gemini", "xai", "perplexity"})
|
|
133
|
-
|
|
134
|
-
#: Provider names with a wired ``mode=cli`` subclass. Mirrors the
|
|
135
|
-
#: routing table in ``_construct_cli_member``; both must stay in sync.
|
|
136
|
-
#: Phase 2 ships ``anthropic``; Phase 3 adds ``openai`` + ``gemini``;
|
|
137
|
-
#: Phase 4 adds ``xai`` + ``perplexity`` (community CLIs, no
|
|
138
|
-
#: subscription savings — they still consume the API key and remain
|
|
139
|
-
#: ``billable=True``).
|
|
140
|
-
_CLI_PROVIDERS = frozenset({"anthropic", "openai", "gemini", "xai", "perplexity"})
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class CouncilDisabledError(RuntimeError):
|
|
144
|
-
"""Raised when ai_council.enabled is false or no member is enabled."""
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def load_settings(
|
|
148
|
-
path: Path = SETTINGS_FILE,
|
|
149
|
-
*,
|
|
150
|
-
ai_council_path: Path = AI_COUNCIL_FILE,
|
|
151
|
-
) -> dict[str, Any]:
|
|
152
|
-
"""Load merged settings via the centralized loader.
|
|
153
|
-
|
|
154
|
-
road-to-portable-dev-preferences P3 migration: tolerance contract
|
|
155
|
-
(missing file / malformed YAML / no PyYAML) is handled uniformly by
|
|
156
|
-
``load_agent_settings``. ``ai_council.*`` keys are not whitelisted,
|
|
157
|
-
so the project file remains authoritative for council config.
|
|
158
|
-
|
|
159
|
-
Step-2 council-redesign overlay: when ``agents/settings/.ai-council.yml``
|
|
160
|
-
exists it is the single source of truth — the validated config is
|
|
161
|
-
synthesized back into ``settings['ai_council']`` and wins over any
|
|
162
|
-
legacy block in ``.agent-settings.yml``. The pre-2 path stays alive
|
|
163
|
-
so the migration breadcrumb in ``.agent-settings.yml`` can ship
|
|
164
|
-
independently.
|
|
165
|
-
"""
|
|
166
|
-
from scripts._lib.agent_settings import load_agent_settings
|
|
167
|
-
settings = load_agent_settings(project_path=path)
|
|
168
|
-
if ai_council_path.exists():
|
|
169
|
-
cfg = load_council_config(ai_council_path)
|
|
170
|
-
settings["ai_council"] = _synthesize_ai_council_block(cfg)
|
|
171
|
-
return settings
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
def _synthesize_ai_council_block(cfg: CouncilConfig) -> dict[str, Any]:
|
|
175
|
-
"""Project a validated ``CouncilConfig`` onto the legacy dict shape.
|
|
176
|
-
|
|
177
|
-
``build_members`` and the ``_resolve_*`` helpers read the legacy
|
|
178
|
-
``ai_council.*`` keys — keeping the projection identical means no
|
|
179
|
-
downstream caller changes. ``api_key_ref`` is carried through; raw
|
|
180
|
-
keys are never resolved here (resolution is lazy, per enabled
|
|
181
|
-
member, inside ``_construct_api_member``).
|
|
182
|
-
"""
|
|
183
|
-
members: dict[str, dict[str, Any]] = {}
|
|
184
|
-
for name, m in cfg.members.items():
|
|
185
|
-
entry: dict[str, Any] = {"enabled": m.enabled, "model": m.model}
|
|
186
|
-
if m.api_key_ref is not None:
|
|
187
|
-
entry["api_key_ref"] = m.api_key_ref
|
|
188
|
-
if m.mode is not None:
|
|
189
|
-
entry["mode"] = m.mode
|
|
190
|
-
if m.binary is not None:
|
|
191
|
-
entry["binary"] = m.binary
|
|
192
|
-
if m.model_ladder:
|
|
193
|
-
entry["model_ladder"] = list(m.model_ladder)
|
|
194
|
-
members[name] = entry
|
|
195
|
-
advisors: dict[str, dict[str, Any]] = {}
|
|
196
|
-
for name, a in cfg.advisors.items():
|
|
197
|
-
entry = {
|
|
198
|
-
"enabled": a.enabled,
|
|
199
|
-
"member": a.member,
|
|
200
|
-
"persona": a.persona,
|
|
201
|
-
}
|
|
202
|
-
if a.model is not None:
|
|
203
|
-
entry["model"] = a.model
|
|
204
|
-
advisors[name] = entry
|
|
205
|
-
return {
|
|
206
|
-
"enabled": cfg.enabled,
|
|
207
|
-
"mode": cfg.defaults.mode,
|
|
208
|
-
"min_rounds": cfg.defaults.min_rounds,
|
|
209
|
-
"deep_min_rounds": cfg.defaults.deep_min_rounds,
|
|
210
|
-
"max_output_tokens": cfg.defaults.max_output_tokens,
|
|
211
|
-
"session_retention_days": cfg.defaults.session_retention_days,
|
|
212
|
-
"debate_max_rounds": cfg.defaults.debate_max_rounds,
|
|
213
|
-
"cost_budget": {
|
|
214
|
-
"max_input_tokens": cfg.cost_budget.max_input_tokens,
|
|
215
|
-
"max_output_tokens": cfg.cost_budget.max_output_tokens,
|
|
216
|
-
"max_calls": cfg.cost_budget.max_calls,
|
|
217
|
-
"max_total_usd": cfg.cost_budget.max_total_usd,
|
|
218
|
-
},
|
|
219
|
-
"consensus_scoring": {
|
|
220
|
-
"enabled": cfg.consensus_scoring.enabled,
|
|
221
|
-
"strong_threshold": cfg.consensus_scoring.strong_threshold,
|
|
222
|
-
"minority_threshold": cfg.consensus_scoring.minority_threshold,
|
|
223
|
-
"lenses": list(cfg.consensus_scoring.lenses),
|
|
224
|
-
},
|
|
225
|
-
"cli_call_budget": {
|
|
226
|
-
"max_calls_per_day": dict(cfg.cli_call_budget.max_calls_per_day),
|
|
227
|
-
"warn_at": cfg.cli_call_budget.warn_at,
|
|
228
|
-
},
|
|
229
|
-
"necessity_classifier": {
|
|
230
|
-
"enabled": cfg.necessity_classifier.enabled,
|
|
231
|
-
"mode": cfg.necessity_classifier.mode,
|
|
232
|
-
"user_explicit_mode": cfg.necessity_classifier.user_explicit_mode,
|
|
233
|
-
},
|
|
234
|
-
"model_downgrade": {
|
|
235
|
-
"enabled": cfg.model_downgrade.enabled,
|
|
236
|
-
"auto_apply": cfg.model_downgrade.auto_apply,
|
|
237
|
-
},
|
|
238
|
-
"debate": {
|
|
239
|
-
"max_cost_usd": cfg.debate.max_cost_usd,
|
|
240
|
-
"cost_disclosure": {
|
|
241
|
-
"mode": cfg.debate.cost_disclosure.mode,
|
|
242
|
-
"threshold_usd": cfg.debate.cost_disclosure.threshold_usd,
|
|
243
|
-
"show_per_member": cfg.debate.cost_disclosure.show_per_member,
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
"lens_overrides": {
|
|
247
|
-
"necessity_classifier_mode": dict(
|
|
248
|
-
cfg.lens_overrides.necessity_classifier_mode,
|
|
249
|
-
),
|
|
250
|
-
"necessity_classifier_user_explicit_mode": dict(
|
|
251
|
-
cfg.lens_overrides.necessity_classifier_user_explicit_mode,
|
|
252
|
-
),
|
|
253
|
-
"model_downgrade": {
|
|
254
|
-
lens: {"enabled": md.enabled, "auto_apply": md.auto_apply}
|
|
255
|
-
for lens, md in cfg.lens_overrides.model_downgrade.items()
|
|
256
|
-
},
|
|
257
|
-
"cost_disclosure": {
|
|
258
|
-
lens: {
|
|
259
|
-
"mode": cd.mode,
|
|
260
|
-
"threshold_usd": cd.threshold_usd,
|
|
261
|
-
"show_per_member": cd.show_per_member,
|
|
262
|
-
}
|
|
263
|
-
for lens, cd in cfg.lens_overrides.cost_disclosure.items()
|
|
264
|
-
},
|
|
265
|
-
},
|
|
266
|
-
"members": members,
|
|
267
|
-
"advisors": advisors,
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
def build_members(
|
|
272
|
-
settings: dict[str, Any],
|
|
273
|
-
*,
|
|
274
|
-
invocation_mode: str | None = None,
|
|
275
|
-
model_overrides: dict[str, str] | None = None,
|
|
276
|
-
siblings_overrides: dict[str, list[str]] | None = None,
|
|
277
|
-
skipped: list[dict[str, Any]] | None = None,
|
|
278
|
-
) -> list[ExternalAIClient]:
|
|
279
|
-
"""Construct enabled council members from settings.
|
|
280
|
-
|
|
281
|
-
Honours `ai_council.enabled` (master switch) and per-member
|
|
282
|
-
`enabled` flags. Raises `CouncilDisabledError` when the council is
|
|
283
|
-
off or no member is wired up.
|
|
284
|
-
|
|
285
|
-
`model_overrides` is a per-invocation `{member_name: model_id}`
|
|
286
|
-
map that wins over the per-member `model` in settings. Members not
|
|
287
|
-
listed fall back to the settings value, then the per-client default.
|
|
288
|
-
|
|
289
|
-
`siblings_overrides` is a per-invocation `{member_name: [model, ...]}`
|
|
290
|
-
map that fans the named provider out to multiple sibling models in
|
|
291
|
-
one run (e.g. claude-sonnet-4-5 + claude-opus-4-1). Each model
|
|
292
|
-
becomes its own billable member with independent cost tracking.
|
|
293
|
-
Mutually exclusive with `model_overrides` for the same provider;
|
|
294
|
-
requires `mode=api`; provider must be enabled in settings.
|
|
295
|
-
|
|
296
|
-
`skipped` is an optional caller-owned list. When provided, each
|
|
297
|
-
cli-mode member that fails to construct (binary missing) is appended
|
|
298
|
-
as `{"member": <name>, "reason": "binary_missing", "detail": <msg>}`
|
|
299
|
-
instead of crashing the loop. The skip is also surfaced on stderr
|
|
300
|
-
as `[council] SKIP <name>: <detail>` so the run log carries it
|
|
301
|
-
even when the caller passes ``None``. Phase 5 Step 2 contract:
|
|
302
|
-
a missing CLI binary degrades that member only — never silently
|
|
303
|
-
drops, never crashes the whole council unless every configured
|
|
304
|
-
member ends up skipped.
|
|
305
|
-
"""
|
|
306
|
-
ai = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
|
|
307
|
-
if not ai.get("enabled"):
|
|
308
|
-
raise CouncilDisabledError(
|
|
309
|
-
"ai_council.enabled is false in .agent-settings.yml — "
|
|
310
|
-
"flip it on before invoking council:* commands."
|
|
311
|
-
)
|
|
312
|
-
members_cfg = ai.get("members") or {}
|
|
313
|
-
global_mode = ai.get("mode")
|
|
314
|
-
cli_budget_cfg = (ai.get("cli_call_budget") or {}) if isinstance(ai, dict) else {}
|
|
315
|
-
cli_caps = (cli_budget_cfg.get("max_calls_per_day") or {}) if isinstance(cli_budget_cfg, dict) else {}
|
|
316
|
-
cli_warn_at = float(cli_budget_cfg.get("warn_at", 0.8)) if isinstance(cli_budget_cfg, dict) else 0.8
|
|
317
|
-
overrides = model_overrides or {}
|
|
318
|
-
siblings = siblings_overrides or {}
|
|
319
|
-
unknown = set(overrides) - set(members_cfg)
|
|
320
|
-
if unknown:
|
|
321
|
-
raise CouncilDisabledError(
|
|
322
|
-
f"--model targets unknown member(s) {sorted(unknown)!r}; "
|
|
323
|
-
f"known members: {sorted(members_cfg)!r}."
|
|
324
|
-
)
|
|
325
|
-
unknown_sib = set(siblings) - set(members_cfg)
|
|
326
|
-
if unknown_sib:
|
|
327
|
-
raise CouncilDisabledError(
|
|
328
|
-
f"--siblings targets unknown member(s) {sorted(unknown_sib)!r}; "
|
|
329
|
-
f"known members: {sorted(members_cfg)!r}."
|
|
330
|
-
)
|
|
331
|
-
conflict = set(overrides) & set(siblings)
|
|
332
|
-
if conflict:
|
|
333
|
-
raise CouncilDisabledError(
|
|
334
|
-
f"--model and --siblings target the same member(s) {sorted(conflict)!r}; "
|
|
335
|
-
f"pick one per provider per invocation."
|
|
336
|
-
)
|
|
337
|
-
members: list[ExternalAIClient] = []
|
|
338
|
-
for name, cfg in members_cfg.items():
|
|
339
|
-
cfg = cfg or {}
|
|
340
|
-
if not cfg.get("enabled"):
|
|
341
|
-
if name in siblings:
|
|
342
|
-
raise CouncilDisabledError(
|
|
343
|
-
f"--siblings targets member {name!r} but it is not "
|
|
344
|
-
f"enabled in .agent-settings.yml (ai_council.members.{name}.enabled)."
|
|
345
|
-
)
|
|
346
|
-
continue
|
|
347
|
-
mode = resolve_mode(
|
|
348
|
-
name,
|
|
349
|
-
invocation_mode=invocation_mode,
|
|
350
|
-
member_settings=cfg,
|
|
351
|
-
global_mode=global_mode,
|
|
352
|
-
)
|
|
353
|
-
if name in siblings:
|
|
354
|
-
if mode != "api":
|
|
355
|
-
raise CouncilDisabledError(
|
|
356
|
-
f"--siblings requires mode=api for member {name!r} (got {mode!r})."
|
|
357
|
-
)
|
|
358
|
-
api_key_ref = cfg.get("api_key_ref")
|
|
359
|
-
for sib_model in siblings[name]:
|
|
360
|
-
members.append(
|
|
361
|
-
_construct_api_member(name, sib_model, api_key_ref=api_key_ref),
|
|
362
|
-
)
|
|
363
|
-
continue
|
|
364
|
-
model = overrides.get(name) or cfg.get("model")
|
|
365
|
-
if mode == "api" and name in _API_PROVIDERS:
|
|
366
|
-
members.append(
|
|
367
|
-
_construct_api_member(name, model, api_key_ref=cfg.get("api_key_ref")),
|
|
368
|
-
)
|
|
369
|
-
elif mode == "cli" and name in _CLI_PROVIDERS:
|
|
370
|
-
try:
|
|
371
|
-
members.append(
|
|
372
|
-
_construct_cli_member(
|
|
373
|
-
name,
|
|
374
|
-
model,
|
|
375
|
-
binary=cfg.get("binary"),
|
|
376
|
-
max_calls_per_day=cli_caps.get(name),
|
|
377
|
-
warn_at=cli_warn_at,
|
|
378
|
-
),
|
|
379
|
-
)
|
|
380
|
-
except CliClientError as exc:
|
|
381
|
-
_, _, display = _CLI_FACTORY[name]
|
|
382
|
-
detail = (
|
|
383
|
-
f"{exc} Install the {display} CLI or flip "
|
|
384
|
-
f"ai_council.members.{name}.mode back to 'api'."
|
|
385
|
-
)
|
|
386
|
-
entry = {
|
|
387
|
-
"member": name,
|
|
388
|
-
"reason": "binary_missing",
|
|
389
|
-
"detail": detail,
|
|
390
|
-
}
|
|
391
|
-
if skipped is not None:
|
|
392
|
-
skipped.append(entry)
|
|
393
|
-
print(f"[council] SKIP {name}: {detail}", file=sys.stderr)
|
|
394
|
-
continue
|
|
395
|
-
elif mode == "cli":
|
|
396
|
-
raise CouncilDisabledError(
|
|
397
|
-
f"member {name!r} resolves to mode=cli but no CLI client is "
|
|
398
|
-
f"wired (known: {sorted(_CLI_PROVIDERS)!r})."
|
|
399
|
-
)
|
|
400
|
-
elif mode == "manual":
|
|
401
|
-
members.append(ManualClient(name=name, model=model or "manual"))
|
|
402
|
-
elif mode == "playwright":
|
|
403
|
-
raise CouncilDisabledError(
|
|
404
|
-
f"member {name!r} resolves to mode=playwright (Phase 2c, not wired)."
|
|
405
|
-
)
|
|
406
|
-
else:
|
|
407
|
-
raise CouncilDisabledError(
|
|
408
|
-
f"member {name!r} has no transport — mode={mode}, "
|
|
409
|
-
f"name not in {sorted(_API_PROVIDERS)!r}."
|
|
410
|
-
)
|
|
411
|
-
if not members:
|
|
412
|
-
if skipped:
|
|
413
|
-
names = ", ".join(s["member"] for s in skipped)
|
|
414
|
-
raise CouncilDisabledError(
|
|
415
|
-
f"no council member could be constructed — every enabled "
|
|
416
|
-
f"member was skipped ({names}). See [council] SKIP entries "
|
|
417
|
-
f"on stderr for the per-member reason."
|
|
418
|
-
)
|
|
419
|
-
raise CouncilDisabledError(
|
|
420
|
-
"no council member has `enabled: true` — enable at least one in "
|
|
421
|
-
".agent-settings.yml under ai_council.members.*."
|
|
422
|
-
)
|
|
423
|
-
return members
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
def _build_advisor_plans(
|
|
427
|
-
ai_cfg: dict[str, Any],
|
|
428
|
-
repo_root: Path,
|
|
429
|
-
) -> dict[str, AdvisorPlan]:
|
|
430
|
-
"""Reconstruct AdvisorConfig from the projected dict, then plan swaps.
|
|
431
|
-
|
|
432
|
-
The legacy ``ai_council.advisors`` dict shape is the projection
|
|
433
|
-
written by ``_synthesize_ai_council_block``. Disabled advisors are
|
|
434
|
-
silently skipped by ``plan_advisor_swap``; one-per-provider is
|
|
435
|
-
enforced there. Returns empty when no advisor block is present.
|
|
436
|
-
"""
|
|
437
|
-
raw = ai_cfg.get("advisors") if isinstance(ai_cfg, dict) else None
|
|
438
|
-
if not raw:
|
|
439
|
-
return {}
|
|
440
|
-
advisors: dict[str, AdvisorConfig] = {}
|
|
441
|
-
for name, entry in raw.items():
|
|
442
|
-
if not isinstance(entry, dict):
|
|
443
|
-
continue
|
|
444
|
-
advisors[name] = AdvisorConfig(
|
|
445
|
-
name=name,
|
|
446
|
-
enabled=bool(entry.get("enabled", False)),
|
|
447
|
-
member=str(entry.get("member", "")),
|
|
448
|
-
persona=str(entry.get("persona", "")),
|
|
449
|
-
model=entry.get("model"),
|
|
450
|
-
)
|
|
451
|
-
return plan_advisor_swap(advisors, repo_root)
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
def _advisor_model_overrides(
|
|
455
|
-
plans: dict[str, AdvisorPlan],
|
|
456
|
-
explicit: dict[str, str] | None,
|
|
457
|
-
) -> dict[str, str]:
|
|
458
|
-
"""Merge advisor model_overrides under explicit ``--model`` flags.
|
|
459
|
-
|
|
460
|
-
Explicit CLI ``--model`` overrides win over advisor-bound model
|
|
461
|
-
overrides — the user's flag is always authoritative.
|
|
462
|
-
"""
|
|
463
|
-
merged: dict[str, str] = {}
|
|
464
|
-
for member, plan in plans.items():
|
|
465
|
-
if plan.model_override:
|
|
466
|
-
merged[member] = plan.model_override
|
|
467
|
-
if explicit:
|
|
468
|
-
merged.update(explicit)
|
|
469
|
-
return merged
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
def _format_advisor_summary(
|
|
473
|
-
plans: dict[str, AdvisorPlan],
|
|
474
|
-
members: list[ExternalAIClient],
|
|
475
|
-
) -> str:
|
|
476
|
-
"""Render the ``advisor: <persona> on <member> via <model>`` lines."""
|
|
477
|
-
if not plans:
|
|
478
|
-
return ""
|
|
479
|
-
member_models = {m.name: m.model for m in members}
|
|
480
|
-
rows: list[str] = []
|
|
481
|
-
for member, plan in plans.items():
|
|
482
|
-
model = member_models.get(member, plan.model_override or "?")
|
|
483
|
-
rows.append(
|
|
484
|
-
f" advisor: {plan.display_name} on {member} via {model}"
|
|
485
|
-
)
|
|
486
|
-
return "\n".join(rows)
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
def _construct_api_member(
|
|
490
|
-
name: str,
|
|
491
|
-
model: str | None,
|
|
492
|
-
*,
|
|
493
|
-
api_key_ref: str | None = None,
|
|
494
|
-
) -> ExternalAIClient:
|
|
495
|
-
"""Build an api-mode client for a known provider name.
|
|
496
|
-
|
|
497
|
-
``api_key_ref`` carries the validated ``file:<path>`` / ``env:<VAR>``
|
|
498
|
-
reference from ``agents/settings/.ai-council.yml`` and is resolved lazily here
|
|
499
|
-
so the council does not require keys for disabled providers. When
|
|
500
|
-
``api_key_ref`` is ``None`` (no new config yet, or legacy code path),
|
|
501
|
-
fall back to the per-provider loaders so the pre-step-2
|
|
502
|
-
``.agent-settings.yml`` flow keeps working during migration. Tests
|
|
503
|
-
monkeypatch the legacy loaders — that path stays intact.
|
|
504
|
-
"""
|
|
505
|
-
if name == "anthropic":
|
|
506
|
-
api_key = (
|
|
507
|
-
resolve_api_key(api_key_ref, scope="ai_council.members.anthropic")
|
|
508
|
-
if api_key_ref else load_anthropic_key()
|
|
509
|
-
)
|
|
510
|
-
return AnthropicClient(model=model or "claude-sonnet-4-5", api_key=api_key)
|
|
511
|
-
if name == "openai":
|
|
512
|
-
api_key = (
|
|
513
|
-
resolve_api_key(api_key_ref, scope="ai_council.members.openai")
|
|
514
|
-
if api_key_ref else load_openai_key()
|
|
515
|
-
)
|
|
516
|
-
return OpenAIClient(model=model or "gpt-4o", api_key=api_key)
|
|
517
|
-
if name == "gemini":
|
|
518
|
-
if not api_key_ref:
|
|
519
|
-
raise CouncilDisabledError(
|
|
520
|
-
"member 'gemini' requires api_key_ref in agents/settings/.ai-council.yml "
|
|
521
|
-
"(e.g. `env:GEMINI_API_KEY`) — no legacy fallback."
|
|
522
|
-
)
|
|
523
|
-
api_key = resolve_api_key(api_key_ref, scope="ai_council.members.gemini")
|
|
524
|
-
return GeminiClient(model=model or "gemini-2.5-pro", api_key=api_key)
|
|
525
|
-
if name == "xai":
|
|
526
|
-
if not api_key_ref:
|
|
527
|
-
raise CouncilDisabledError(
|
|
528
|
-
"member 'xai' requires api_key_ref in agents/settings/.ai-council.yml "
|
|
529
|
-
"(e.g. `env:XAI_API_KEY`) — no legacy fallback."
|
|
530
|
-
)
|
|
531
|
-
api_key = resolve_api_key(api_key_ref, scope="ai_council.members.xai")
|
|
532
|
-
return XAIClient(model=model or "grok-4", api_key=api_key)
|
|
533
|
-
if name == "perplexity":
|
|
534
|
-
if not api_key_ref:
|
|
535
|
-
raise CouncilDisabledError(
|
|
536
|
-
"member 'perplexity' requires api_key_ref in agents/settings/.ai-council.yml "
|
|
537
|
-
"(e.g. `env:PERPLEXITY_API_KEY`) — no legacy fallback."
|
|
538
|
-
)
|
|
539
|
-
api_key = resolve_api_key(api_key_ref, scope="ai_council.members.perplexity")
|
|
540
|
-
return PerplexityClient(model=model or "sonar-pro", api_key=api_key)
|
|
541
|
-
raise CouncilDisabledError(
|
|
542
|
-
f"member {name!r} has no api transport "
|
|
543
|
-
f"(known: {sorted(_API_PROVIDERS)!r})."
|
|
544
|
-
)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
#: Provider → (class-attribute-name, default_model, human_display) for
|
|
548
|
-
#: cli-mode routing. The class ref is looked up via ``getattr`` on this
|
|
549
|
-
#: module at call time so ``monkeypatch.setattr(council_cli, "AnthropicCliClient", X)``
|
|
550
|
-
#: keeps working from tests. The display string is used by
|
|
551
|
-
#: ``build_members`` to render the "Install the <X> CLI" hint in
|
|
552
|
-
#: skip-with-reason logs without re-importing every subclass at the
|
|
553
|
-
#: call site.
|
|
554
|
-
_CLI_FACTORY: dict[str, tuple[str, str, str]] = {
|
|
555
|
-
"anthropic": ("AnthropicCliClient", "claude-sonnet-4-5", "Claude"),
|
|
556
|
-
"openai": ("OpenAICliClient", "gpt-5", "Codex"),
|
|
557
|
-
"gemini": ("GeminiCliClient", "gemini-2.5-pro", "Gemini"),
|
|
558
|
-
"xai": ("XAICliClient", "grok-4", "Grok (community)"),
|
|
559
|
-
"perplexity": ("PerplexityCliClient", "sonar-pro", "Perplexity (community)"),
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
def _construct_cli_member(
|
|
564
|
-
name: str,
|
|
565
|
-
model: str | None,
|
|
566
|
-
*,
|
|
567
|
-
binary: str | None = None,
|
|
568
|
-
max_calls_per_day: int | None = None,
|
|
569
|
-
warn_at: float = 0.8,
|
|
570
|
-
) -> ExternalAIClient:
|
|
571
|
-
"""Build a cli-mode client for a known provider name.
|
|
572
|
-
|
|
573
|
-
``binary`` overrides the provider default (e.g. ``/opt/claude``);
|
|
574
|
-
``None`` falls through to ``shutil.which(default_binary)``. The
|
|
575
|
-
daily quota is plumbed through to the subclass; ``None`` disables
|
|
576
|
-
the local counter (only stderr-based quota detection remains).
|
|
577
|
-
``warn_at`` (step-8 P1) is the fractional threshold flipping the
|
|
578
|
-
pre-run quota summary to its ``⚠️`` shape; default 0.8 mirrors
|
|
579
|
-
``CliCallBudgetConfig``.
|
|
580
|
-
Lets the subclass' ``CliClientError`` propagate so ``build_members``
|
|
581
|
-
can convert it into a structured per-member skip entry without
|
|
582
|
-
crashing the whole council (the original "fail loudly for the
|
|
583
|
-
entire council" contract is preserved when no other member
|
|
584
|
-
survives — the empty-members guard at the end of ``build_members``
|
|
585
|
-
fires with the skip log attached).
|
|
586
|
-
"""
|
|
587
|
-
if name in _CLI_FACTORY:
|
|
588
|
-
attr, default_model, _display = _CLI_FACTORY[name]
|
|
589
|
-
cls = globals()[attr]
|
|
590
|
-
return cls(
|
|
591
|
-
model=model or default_model,
|
|
592
|
-
binary=binary,
|
|
593
|
-
max_calls_per_day=max_calls_per_day,
|
|
594
|
-
warn_at=warn_at,
|
|
595
|
-
)
|
|
596
|
-
raise CouncilDisabledError(
|
|
597
|
-
f"member {name!r} has no cli transport "
|
|
598
|
-
f"(known: {sorted(_CLI_PROVIDERS)!r})."
|
|
599
|
-
)
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
def build_question(
|
|
603
|
-
*,
|
|
604
|
-
input_path: Path,
|
|
605
|
-
input_mode: str,
|
|
606
|
-
max_tokens: int,
|
|
607
|
-
prompt_mode_override: str | None = None,
|
|
608
|
-
) -> tuple[CouncilQuestion, str]:
|
|
609
|
-
"""Bundle the input file. Returns (question, artefact_label).
|
|
610
|
-
|
|
611
|
-
`prompt_mode_override` swaps the per-mode neutrality addendum looked
|
|
612
|
-
up by `system_prompt_for(question.mode, ...)`. The bundle shape is
|
|
613
|
-
unchanged — the bundler still uses `input_mode` to format the
|
|
614
|
-
artefact. Routed by the `/council pr|design|optimize|analysis`
|
|
615
|
-
wrappers via the `--prompt-mode` CLI flag.
|
|
616
|
-
"""
|
|
617
|
-
if input_mode == "prompt":
|
|
618
|
-
text = input_path.read_text(encoding="utf-8")
|
|
619
|
-
ctx = bundle_prompt(text)
|
|
620
|
-
artefact = str(input_path)
|
|
621
|
-
elif input_mode == "roadmap":
|
|
622
|
-
ctx = bundle_roadmap(input_path)
|
|
623
|
-
artefact = str(input_path)
|
|
624
|
-
else:
|
|
625
|
-
raise ValueError(
|
|
626
|
-
f"unsupported input mode: {input_mode!r} (use prompt | roadmap)"
|
|
627
|
-
)
|
|
628
|
-
mode = prompt_mode_override or ctx.mode
|
|
629
|
-
return CouncilQuestion(mode=mode, user_prompt=ctx.text,
|
|
630
|
-
max_tokens=max_tokens), artefact
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
def format_estimate_table(
|
|
634
|
-
members: list[ExternalAIClient],
|
|
635
|
-
estimates: list[Any],
|
|
636
|
-
*,
|
|
637
|
-
consensus_delta_usd: float = 0.0,
|
|
638
|
-
consensus_extra_calls: int = 0,
|
|
639
|
-
peer_review_delta_usd: float = 0.0,
|
|
640
|
-
peer_review_extra_calls: int = 0,
|
|
641
|
-
) -> str:
|
|
642
|
-
rows = [
|
|
643
|
-
f" {m.name}/{m.model}: "
|
|
644
|
-
f"~{e.input_tokens} in + {e.output_tokens} out = ${e.total_usd:.4f}"
|
|
645
|
-
for m, e in zip(members, estimates)
|
|
646
|
-
]
|
|
647
|
-
total = sum(e.total_usd for e in estimates)
|
|
648
|
-
if consensus_extra_calls > 0:
|
|
649
|
-
rows.append(
|
|
650
|
-
f" +consensus scoring: +{consensus_extra_calls} calls "
|
|
651
|
-
f"(~+${consensus_delta_usd:.4f})"
|
|
652
|
-
)
|
|
653
|
-
total += consensus_delta_usd
|
|
654
|
-
if peer_review_extra_calls > 0:
|
|
655
|
-
rows.append(
|
|
656
|
-
f" +peer-review: +{peer_review_extra_calls} calls "
|
|
657
|
-
f"(~+${peer_review_delta_usd:.4f})"
|
|
658
|
-
)
|
|
659
|
-
total += peer_review_delta_usd
|
|
660
|
-
rows.append(f" TOTAL: ${total:.4f}")
|
|
661
|
-
return "\n".join(rows)
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
def _consensus_cost_delta(
|
|
665
|
-
ai_cfg: dict[str, Any],
|
|
666
|
-
prompt_mode: str,
|
|
667
|
-
estimates: list[Any],
|
|
668
|
-
n_billable: int,
|
|
669
|
-
) -> tuple[int, float]:
|
|
670
|
-
"""Return ``(extra_calls, extra_usd)`` for the consensus round.
|
|
671
|
-
|
|
672
|
-
Active when ``ai_council.consensus_scoring.enabled`` is true AND the
|
|
673
|
-
invocation's lens is in ``consensus_scoring.lenses``. Each member
|
|
674
|
-
contributes two extra calls (extraction + scoring); the worst-case
|
|
675
|
-
cost uses the base per-member estimate as a ceiling.
|
|
676
|
-
"""
|
|
677
|
-
cs = ai_cfg.get("consensus_scoring") or {}
|
|
678
|
-
if not cs.get("enabled"):
|
|
679
|
-
return 0, 0.0
|
|
680
|
-
lenses = cs.get("lenses") or ["analysis"]
|
|
681
|
-
if prompt_mode not in lenses:
|
|
682
|
-
return 0, 0.0
|
|
683
|
-
extra_calls = 2 * n_billable
|
|
684
|
-
extra_usd = 2.0 * sum(e.total_usd for e in estimates)
|
|
685
|
-
return extra_calls, extra_usd
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
def _maybe_run_consensus(
|
|
689
|
-
ai_cfg: dict[str, Any],
|
|
690
|
-
question: CouncilQuestion,
|
|
691
|
-
members: list[ExternalAIClient],
|
|
692
|
-
responses: list[CouncilResponse],
|
|
693
|
-
budget: CostBudget,
|
|
694
|
-
table: PriceTable,
|
|
695
|
-
project: Any,
|
|
696
|
-
args: argparse.Namespace,
|
|
697
|
-
) -> ConsensusResult | None:
|
|
698
|
-
"""Run the consensus scoring round when enabled for this lens."""
|
|
699
|
-
cs = ai_cfg.get("consensus_scoring") or {}
|
|
700
|
-
if not cs.get("enabled"):
|
|
701
|
-
return None
|
|
702
|
-
lenses = cs.get("lenses") or ["analysis"]
|
|
703
|
-
if question.mode not in lenses:
|
|
704
|
-
return None
|
|
705
|
-
return run_consensus_scoring(
|
|
706
|
-
members, responses,
|
|
707
|
-
budget=budget, table=table, project=project,
|
|
708
|
-
original_ask=args.original_ask,
|
|
709
|
-
max_tokens=question.max_tokens,
|
|
710
|
-
strong_threshold=float(cs.get("strong_threshold", 0.7)),
|
|
711
|
-
minority_threshold=float(cs.get("minority_threshold", 0.4)),
|
|
712
|
-
)
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
def _serialise_consensus(consensus: ConsensusResult) -> dict[str, Any]:
|
|
716
|
-
"""Project ConsensusResult onto a JSON-safe dict for session payloads."""
|
|
717
|
-
return {
|
|
718
|
-
"findings": [
|
|
719
|
-
{"id": f.id, "source": f.source, "text": f.text}
|
|
720
|
-
for f in consensus.findings
|
|
721
|
-
],
|
|
722
|
-
"scores": [
|
|
723
|
-
{
|
|
724
|
-
"finding_id": s.finding_id, "scorer": s.scorer,
|
|
725
|
-
"score": s.score, "agree": s.agree, "reason": s.reason,
|
|
726
|
-
}
|
|
727
|
-
for s in consensus.scores
|
|
728
|
-
],
|
|
729
|
-
"metadata": {
|
|
730
|
-
fid: {
|
|
731
|
-
"mean_score": m.mean_score,
|
|
732
|
-
"agreement_rate": m.agreement_rate,
|
|
733
|
-
"consensus_strength": m.consensus_strength,
|
|
734
|
-
"dissent_count": m.dissent_count,
|
|
735
|
-
"scorers": list(m.scorers),
|
|
736
|
-
"concur_count": m.concur_count,
|
|
737
|
-
"dissent_reasons": [list(pair) for pair in m.dissent_reasons],
|
|
738
|
-
"evidence_quality": m.evidence_quality,
|
|
739
|
-
}
|
|
740
|
-
for fid, m in consensus.metadata.items()
|
|
741
|
-
},
|
|
742
|
-
"extraction_responses": _serialise_responses(consensus.extraction_responses),
|
|
743
|
-
"scoring_responses": _serialise_responses(consensus.scoring_responses),
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
def _decision_replay_settings(
|
|
748
|
-
ai_cfg: dict[str, Any], lens: str,
|
|
749
|
-
) -> tuple[bool, bool]:
|
|
750
|
-
"""Resolve (enabled, include_member_arguments) for ``lens``.
|
|
751
|
-
|
|
752
|
-
Per-lens override under ``lenses.<lens>.decision_replay`` beats the
|
|
753
|
-
global ``decision_replay`` block. Defaults: enabled=True,
|
|
754
|
-
include_member_arguments=True (Phase 9 ships ON by default — the
|
|
755
|
-
artefact is the audit trail GPT review of PR #148 called out as
|
|
756
|
-
missing).
|
|
757
|
-
"""
|
|
758
|
-
global_block = ai_cfg.get("decision_replay") or {}
|
|
759
|
-
enabled = global_block.get("enabled", True)
|
|
760
|
-
include_args = global_block.get("include_member_arguments", True)
|
|
761
|
-
lenses = ai_cfg.get("lenses") or {}
|
|
762
|
-
lens_block = (lenses.get(lens) or {}).get("decision_replay")
|
|
763
|
-
if isinstance(lens_block, dict):
|
|
764
|
-
if "enabled" in lens_block:
|
|
765
|
-
enabled = lens_block["enabled"]
|
|
766
|
-
if "include_member_arguments" in lens_block:
|
|
767
|
-
include_args = lens_block["include_member_arguments"]
|
|
768
|
-
return bool(enabled), bool(include_args)
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
def _maybe_write_decision_replay(
|
|
772
|
-
*,
|
|
773
|
-
ai_cfg: dict[str, Any],
|
|
774
|
-
lens: str,
|
|
775
|
-
out_path: Path,
|
|
776
|
-
consensus: ConsensusResult | None,
|
|
777
|
-
deliberation: list[CouncilResponse],
|
|
778
|
-
original_ask: str,
|
|
779
|
-
) -> Path | None:
|
|
780
|
-
"""Write ``decision-replay.md`` alongside ``out_path`` when enabled.
|
|
781
|
-
|
|
782
|
-
No-op when ``decision_replay.enabled`` resolves to ``False`` for the
|
|
783
|
-
lens or when ``consensus`` is ``None`` (nothing to replay). Returns
|
|
784
|
-
the artefact path on success, ``None`` otherwise.
|
|
785
|
-
"""
|
|
786
|
-
enabled, include_args = _decision_replay_settings(ai_cfg, lens)
|
|
787
|
-
if not enabled or consensus is None:
|
|
788
|
-
return None
|
|
789
|
-
replay = render_decision_replay(
|
|
790
|
-
DecisionReplayInputs(
|
|
791
|
-
findings=list(consensus.findings),
|
|
792
|
-
scores=list(consensus.scores),
|
|
793
|
-
metadata=dict(consensus.metadata),
|
|
794
|
-
deliberation=deliberation,
|
|
795
|
-
original_ask=original_ask,
|
|
796
|
-
include_member_arguments=include_args,
|
|
797
|
-
),
|
|
798
|
-
)
|
|
799
|
-
target = out_path.parent / "decision-replay.md"
|
|
800
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
801
|
-
target.write_text(replay, encoding="utf-8")
|
|
802
|
-
return target
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
# ── peer-review (Phase 5 / F1, Karpathy anonymous review) ──────────
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
def _peer_review_active(ai_cfg: dict[str, Any], args: argparse.Namespace) -> bool:
|
|
809
|
-
"""Return True when peer-review should fire for this invocation.
|
|
810
|
-
|
|
811
|
-
Resolution chain (highest priority first):
|
|
812
|
-
1. ``--peer-review`` CLI flag — explicit opt-in.
|
|
813
|
-
2. ``ai_council.peer_review.enabled: true`` in
|
|
814
|
-
``agents/settings/.ai-council.yml`` — opt-in via config.
|
|
815
|
-
Both default to false; peer-review is opt-in by R2 verdict.
|
|
816
|
-
"""
|
|
817
|
-
if getattr(args, "peer_review", False):
|
|
818
|
-
return True
|
|
819
|
-
pr_cfg = ai_cfg.get("peer_review") or {}
|
|
820
|
-
return bool(pr_cfg.get("enabled"))
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
def _peer_review_cost_delta(
|
|
824
|
-
ai_cfg: dict[str, Any],
|
|
825
|
-
args: argparse.Namespace,
|
|
826
|
-
estimates: list[Any],
|
|
827
|
-
n_billable: int,
|
|
828
|
-
) -> tuple[int, float]:
|
|
829
|
-
"""Return ``(extra_calls, extra_usd)`` for the peer-review round.
|
|
830
|
-
|
|
831
|
-
One extra call per billable member (each reviews the others). The
|
|
832
|
-
worst-case cost uses the base per-member estimate as a ceiling —
|
|
833
|
-
same heuristic as ``_consensus_cost_delta``.
|
|
834
|
-
"""
|
|
835
|
-
if not _peer_review_active(ai_cfg, args):
|
|
836
|
-
return 0, 0.0
|
|
837
|
-
if n_billable < 2:
|
|
838
|
-
# Need ≥ 2 distinct deliberation outputs for peer-review to
|
|
839
|
-
# have anything to review. The orchestrator no-ops below 2.
|
|
840
|
-
return 0, 0.0
|
|
841
|
-
extra_calls = n_billable
|
|
842
|
-
extra_usd = sum(e.total_usd for e in estimates)
|
|
843
|
-
return extra_calls, extra_usd
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
def _maybe_run_peer_review(
|
|
847
|
-
ai_cfg: dict[str, Any],
|
|
848
|
-
args: argparse.Namespace,
|
|
849
|
-
question: CouncilQuestion,
|
|
850
|
-
members: list[ExternalAIClient],
|
|
851
|
-
responses: list[CouncilResponse],
|
|
852
|
-
budget: CostBudget,
|
|
853
|
-
table: PriceTable,
|
|
854
|
-
project: Any,
|
|
855
|
-
*,
|
|
856
|
-
persona_labels: dict[str, str] | None = None,
|
|
857
|
-
) -> PeerReviewResult | None:
|
|
858
|
-
"""Run the peer-review pass when opted in.
|
|
859
|
-
|
|
860
|
-
No-ops if fewer than 2 successful deliberation responses exist —
|
|
861
|
-
the orchestrator surfaces the empty result in that case.
|
|
862
|
-
|
|
863
|
-
``persona_labels`` (Phase 6) flows through to ``anonymize_responses``
|
|
864
|
-
so advisor-mode runs render as ``Response A (Contrarian)`` instead
|
|
865
|
-
of bare ``Response A``. Plain-member runs pass ``None``.
|
|
866
|
-
"""
|
|
867
|
-
if not _peer_review_active(ai_cfg, args):
|
|
868
|
-
return None
|
|
869
|
-
result = run_peer_review(
|
|
870
|
-
members, responses,
|
|
871
|
-
budget=budget, table=table, project=project,
|
|
872
|
-
original_ask=args.original_ask,
|
|
873
|
-
max_tokens=question.max_tokens,
|
|
874
|
-
persona_labels=persona_labels,
|
|
875
|
-
)
|
|
876
|
-
if not result.responses:
|
|
877
|
-
return None
|
|
878
|
-
return result
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
def _serialise_peer_review(peer_review: PeerReviewResult) -> dict[str, Any]:
|
|
882
|
-
"""Project PeerReviewResult onto a JSON-safe dict for session payloads."""
|
|
883
|
-
return {
|
|
884
|
-
"responses": _serialise_responses(peer_review.responses),
|
|
885
|
-
"label_to_source": dict(peer_review.label_to_source),
|
|
886
|
-
"persona_labels": dict(peer_review.persona_labels),
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
def _deserialise_peer_review(
|
|
891
|
-
data: dict[str, Any] | None,
|
|
892
|
-
) -> PeerReviewResult | None:
|
|
893
|
-
"""Reconstruct a PeerReviewResult from a session payload section.
|
|
894
|
-
|
|
895
|
-
Returns ``None`` for payloads predating Phase 5 or runs where the
|
|
896
|
-
flag was not passed.
|
|
897
|
-
"""
|
|
898
|
-
if not data:
|
|
899
|
-
return None
|
|
900
|
-
return PeerReviewResult(
|
|
901
|
-
responses=_deserialise_responses(data.get("responses") or []),
|
|
902
|
-
label_to_source=dict(data.get("label_to_source") or {}),
|
|
903
|
-
persona_labels=dict(data.get("persona_labels") or {}),
|
|
904
|
-
)
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
# ── subcommands ─────────────────────────────────────────────────────
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
def _resolve_rounds(args: argparse.Namespace, ai_cfg: dict[str, Any]) -> int:
|
|
911
|
-
"""Resolve effective debate round count from CLI args + settings.
|
|
912
|
-
|
|
913
|
-
Resolution chain (highest priority first):
|
|
914
|
-
1. ``--rounds N`` — explicit user override, any value.
|
|
915
|
-
2. ``--depth deep`` — uses ``ai_council.deep_min_rounds``,
|
|
916
|
-
floored at ``min_rounds`` so the deep tier is monotonic.
|
|
917
|
-
3. ``ai_council.min_rounds`` — default 2.
|
|
918
|
-
|
|
919
|
-
Sub-commands (rule/skill/command) declare ``council_depth: deep``
|
|
920
|
-
in their frontmatter; the host agent reads that and translates it
|
|
921
|
-
to ``--depth deep`` on the CLI invocation. The CLI itself stays
|
|
922
|
-
unaware of frontmatter — the contract is the flag.
|
|
923
|
-
"""
|
|
924
|
-
if getattr(args, "rounds", None) is not None:
|
|
925
|
-
return int(args.rounds)
|
|
926
|
-
min_rounds = int(ai_cfg.get("min_rounds", 2))
|
|
927
|
-
if getattr(args, "depth", "standard") == "deep":
|
|
928
|
-
deep = int(ai_cfg.get("deep_min_rounds", min_rounds))
|
|
929
|
-
return max(deep, min_rounds)
|
|
930
|
-
return min_rounds
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
def _resolve_max_tokens(args: argparse.Namespace, ai_cfg: dict[str, Any]) -> int:
|
|
934
|
-
"""Resolve the per-call output budget passed to each member.
|
|
935
|
-
|
|
936
|
-
Resolution chain (highest priority first):
|
|
937
|
-
1. ``--max-tokens N`` — explicit invocation override.
|
|
938
|
-
2. ``ai_council.max_output_tokens`` — settings value (project file
|
|
939
|
-
is authoritative; this key is not user-global-mergeable).
|
|
940
|
-
3. ``DEFAULT_MAX_TOKENS`` — package fallback (2048).
|
|
941
|
-
|
|
942
|
-
A value of ``0`` at any layer means "unlimited"; it is widened to
|
|
943
|
-
``UNLIMITED_TOKENS_FALLBACK`` before reaching the SDK because
|
|
944
|
-
Anthropic rejects ``max_tokens=0``. Estimation uses the same expanded
|
|
945
|
-
value so the cost preview reflects the worst-case ceiling.
|
|
946
|
-
"""
|
|
947
|
-
cli = getattr(args, "max_tokens", None)
|
|
948
|
-
if cli is not None:
|
|
949
|
-
value = int(cli)
|
|
950
|
-
elif "max_output_tokens" in ai_cfg:
|
|
951
|
-
value = int(ai_cfg.get("max_output_tokens") or 0)
|
|
952
|
-
else:
|
|
953
|
-
value = DEFAULT_MAX_TOKENS
|
|
954
|
-
if value <= 0:
|
|
955
|
-
return UNLIMITED_TOKENS_FALLBACK
|
|
956
|
-
return value
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
def cmd_estimate(
|
|
960
|
-
args: argparse.Namespace,
|
|
961
|
-
*,
|
|
962
|
-
settings: dict[str, Any] | None = None,
|
|
963
|
-
members: list[ExternalAIClient] | None = None,
|
|
964
|
-
table: PriceTable | None = None,
|
|
965
|
-
) -> int:
|
|
966
|
-
"""Print per-member cost preview. No API calls."""
|
|
967
|
-
if settings is None:
|
|
968
|
-
settings = load_settings()
|
|
969
|
-
ai_cfg = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
|
|
970
|
-
advisor_plans = _build_advisor_plans(ai_cfg, REPO_ROOT)
|
|
971
|
-
explicit_overrides = _parse_model_overrides(getattr(args, "model", None))
|
|
972
|
-
skipped: list[dict[str, Any]] = []
|
|
973
|
-
if members is None:
|
|
974
|
-
members = build_members(
|
|
975
|
-
settings,
|
|
976
|
-
invocation_mode=args.mode_override,
|
|
977
|
-
model_overrides=_advisor_model_overrides(
|
|
978
|
-
advisor_plans, explicit_overrides,
|
|
979
|
-
),
|
|
980
|
-
siblings_overrides=_parse_siblings_overrides(getattr(args, "siblings", None)),
|
|
981
|
-
skipped=skipped,
|
|
982
|
-
)
|
|
983
|
-
if table is None:
|
|
984
|
-
table = load_prices()
|
|
985
|
-
question, _ = build_question(
|
|
986
|
-
input_path=Path(args.question), input_mode=args.input_mode,
|
|
987
|
-
max_tokens=_resolve_max_tokens(args, ai_cfg),
|
|
988
|
-
prompt_mode_override=getattr(args, "prompt_mode", None),
|
|
989
|
-
)
|
|
990
|
-
project = detect_project_context(REPO_ROOT)
|
|
991
|
-
billable = [m for m in members if getattr(m, "billable", True)]
|
|
992
|
-
estimates = estimate(question, billable, table,
|
|
993
|
-
project=project, original_ask=args.original_ask,
|
|
994
|
-
advisor_plans=advisor_plans)
|
|
995
|
-
if getattr(args, "debate", False):
|
|
996
|
-
return _emit_debate_estimate(
|
|
997
|
-
args, ai_cfg, members, billable, estimates, advisor_plans,
|
|
998
|
-
skipped=skipped,
|
|
999
|
-
)
|
|
1000
|
-
extra_calls, extra_usd = _consensus_cost_delta(
|
|
1001
|
-
ai_cfg, question.mode, estimates, len(billable),
|
|
1002
|
-
)
|
|
1003
|
-
pr_extra_calls, pr_extra_usd = _peer_review_cost_delta(
|
|
1004
|
-
ai_cfg, args, estimates, len(billable),
|
|
1005
|
-
)
|
|
1006
|
-
sys.stdout.write(
|
|
1007
|
-
f"council:estimate · mode={question.mode} · members={len(members)} "
|
|
1008
|
-
f"(billable={len(billable)})\n"
|
|
1009
|
-
)
|
|
1010
|
-
advisor_summary = _format_advisor_summary(advisor_plans, billable)
|
|
1011
|
-
if advisor_summary:
|
|
1012
|
-
sys.stdout.write(advisor_summary + "\n")
|
|
1013
|
-
if skipped:
|
|
1014
|
-
sys.stdout.write(format_install_hints(skipped) + "\n")
|
|
1015
|
-
sys.stdout.write(
|
|
1016
|
-
format_estimate_table(
|
|
1017
|
-
billable, estimates,
|
|
1018
|
-
consensus_delta_usd=extra_usd,
|
|
1019
|
-
consensus_extra_calls=extra_calls,
|
|
1020
|
-
peer_review_delta_usd=pr_extra_usd,
|
|
1021
|
-
peer_review_extra_calls=pr_extra_calls,
|
|
1022
|
-
) + "\n"
|
|
1023
|
-
)
|
|
1024
|
-
return 0
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
def _emit_debate_estimate(
|
|
1028
|
-
args: argparse.Namespace,
|
|
1029
|
-
ai_cfg: dict[str, Any],
|
|
1030
|
-
members: list[ExternalAIClient],
|
|
1031
|
-
billable: list[ExternalAIClient],
|
|
1032
|
-
estimates: list[Any],
|
|
1033
|
-
advisor_plans: Any,
|
|
1034
|
-
*,
|
|
1035
|
-
skipped: list[dict[str, Any]] | None = None,
|
|
1036
|
-
) -> int:
|
|
1037
|
-
"""Render the round-by-round debate cost projection.
|
|
1038
|
-
|
|
1039
|
-
Upper bound only — progressive disclosure may stop the debate early.
|
|
1040
|
-
Cost shape mirrors ``cmd_debate``: one call per billable member per
|
|
1041
|
-
round, default ``ai_council.min_rounds`` (typically 2), capped at
|
|
1042
|
-
``ai_council.debate_max_rounds`` (typically 4).
|
|
1043
|
-
"""
|
|
1044
|
-
min_rounds = int(ai_cfg.get("min_rounds", 2))
|
|
1045
|
-
max_rounds_cap = int(ai_cfg.get("debate_max_rounds", 4))
|
|
1046
|
-
requested = (
|
|
1047
|
-
int(args.rounds) if getattr(args, "rounds", None) is not None
|
|
1048
|
-
else min_rounds
|
|
1049
|
-
)
|
|
1050
|
-
if requested < 1:
|
|
1051
|
-
raise argparse.ArgumentTypeError(
|
|
1052
|
-
f"--rounds must be >= 1 (got {requested})"
|
|
1053
|
-
)
|
|
1054
|
-
if requested > max_rounds_cap:
|
|
1055
|
-
raise argparse.ArgumentTypeError(
|
|
1056
|
-
f"--rounds={requested} exceeds debate_max_rounds={max_rounds_cap}; "
|
|
1057
|
-
f"raise the cap in agents/settings/.ai-council.yml or lower --rounds."
|
|
1058
|
-
)
|
|
1059
|
-
rounds = requested
|
|
1060
|
-
per_round_usd = sum(e.total_usd for e in estimates)
|
|
1061
|
-
projected_total = per_round_usd * rounds
|
|
1062
|
-
sys.stdout.write(
|
|
1063
|
-
f"council:estimate · mode=debate · members={len(members)} "
|
|
1064
|
-
f"(billable={len(billable)}) · rounds={rounds} "
|
|
1065
|
-
f"(cap={max_rounds_cap})\n"
|
|
1066
|
-
)
|
|
1067
|
-
advisor_summary = _format_advisor_summary(advisor_plans, billable)
|
|
1068
|
-
if advisor_summary:
|
|
1069
|
-
sys.stdout.write(advisor_summary + "\n")
|
|
1070
|
-
if skipped:
|
|
1071
|
-
sys.stdout.write(format_install_hints(skipped) + "\n")
|
|
1072
|
-
for round_idx in range(1, rounds + 1):
|
|
1073
|
-
sys.stdout.write(f"\nRound {round_idx} of {rounds}:\n")
|
|
1074
|
-
sys.stdout.write(format_estimate_table(billable, estimates) + "\n")
|
|
1075
|
-
if round_idx < rounds:
|
|
1076
|
-
sys.stdout.write(" " + "─" * 40 + "\n")
|
|
1077
|
-
sys.stdout.write(
|
|
1078
|
-
f"\n PROJECTED TOTAL ({rounds} rounds): ${projected_total:.4f}\n"
|
|
1079
|
-
)
|
|
1080
|
-
sys.stdout.write(
|
|
1081
|
-
" Note: progressive disclosure may stop the debate early; "
|
|
1082
|
-
"this is an upper bound.\n"
|
|
1083
|
-
)
|
|
1084
|
-
return 0
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
def _serialise_responses(responses: list[CouncilResponse]) -> list[dict[str, Any]]:
|
|
1088
|
-
out: list[dict[str, Any]] = []
|
|
1089
|
-
for r in responses:
|
|
1090
|
-
d = asdict(r)
|
|
1091
|
-
# `metadata` may contain non-JSON types; coerce.
|
|
1092
|
-
d["metadata"] = {k: str(v) for k, v in (d.get("metadata") or {}).items()}
|
|
1093
|
-
out.append(d)
|
|
1094
|
-
return out
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
def _deserialise_responses(items: list[dict[str, Any]]) -> list[CouncilResponse]:
|
|
1098
|
-
out: list[CouncilResponse] = []
|
|
1099
|
-
for d in items:
|
|
1100
|
-
out.append(CouncilResponse(
|
|
1101
|
-
provider=d.get("provider", ""),
|
|
1102
|
-
model=d.get("model", ""),
|
|
1103
|
-
text=d.get("text", ""),
|
|
1104
|
-
input_tokens=int(d.get("input_tokens", 0) or 0),
|
|
1105
|
-
output_tokens=int(d.get("output_tokens", 0) or 0),
|
|
1106
|
-
latency_ms=int(d.get("latency_ms", 0) or 0),
|
|
1107
|
-
error=d.get("error"),
|
|
1108
|
-
metadata=dict(d.get("metadata") or {}),
|
|
1109
|
-
))
|
|
1110
|
-
return out
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
def _deserialise_consensus(data: dict[str, Any] | None) -> ConsensusResult | None:
|
|
1114
|
-
"""Reconstruct a ConsensusResult from a serialised payload section.
|
|
1115
|
-
|
|
1116
|
-
Used by ``cmd_render`` to re-render saved sessions that captured a
|
|
1117
|
-
consensus round. Returns ``None`` when the payload predates Phase 4
|
|
1118
|
-
or the round was skipped for the lens.
|
|
1119
|
-
"""
|
|
1120
|
-
if not data:
|
|
1121
|
-
return None
|
|
1122
|
-
from scripts.ai_council.consensus import (
|
|
1123
|
-
ConsensusMetadata, Finding, FindingScore,
|
|
1124
|
-
aggregate_scores, bucket_by_threshold,
|
|
1125
|
-
)
|
|
1126
|
-
findings = [
|
|
1127
|
-
Finding(id=f["id"], source=f["source"], text=f["text"])
|
|
1128
|
-
for f in (data.get("findings") or [])
|
|
1129
|
-
]
|
|
1130
|
-
scores = [
|
|
1131
|
-
FindingScore(
|
|
1132
|
-
finding_id=s["finding_id"], scorer=s["scorer"],
|
|
1133
|
-
score=int(s["score"]), agree=bool(s["agree"]),
|
|
1134
|
-
reason=s.get("reason", ""),
|
|
1135
|
-
)
|
|
1136
|
-
for s in (data.get("scores") or [])
|
|
1137
|
-
]
|
|
1138
|
-
metadata = aggregate_scores(findings, scores)
|
|
1139
|
-
bucket = bucket_by_threshold(findings, metadata)
|
|
1140
|
-
return ConsensusResult(
|
|
1141
|
-
bucket=bucket, findings=findings, scores=scores, metadata=metadata,
|
|
1142
|
-
extraction_responses=_deserialise_responses(
|
|
1143
|
-
data.get("extraction_responses") or [],
|
|
1144
|
-
),
|
|
1145
|
-
scoring_responses=_deserialise_responses(
|
|
1146
|
-
data.get("scoring_responses") or [],
|
|
1147
|
-
),
|
|
1148
|
-
)
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
def _resolve_necessity_mode(
|
|
1152
|
-
ai_cfg: dict[str, Any],
|
|
1153
|
-
lens: str,
|
|
1154
|
-
invocation: str = "agent",
|
|
1155
|
-
) -> tuple[bool, str]:
|
|
1156
|
-
"""Return ``(enabled, effective_mode)`` for the necessity classifier.
|
|
1157
|
-
|
|
1158
|
-
Two-tier resolution (step-8 D2):
|
|
1159
|
-
|
|
1160
|
-
- ``invocation="agent"`` → reads ``necessity_classifier.mode`` with
|
|
1161
|
-
per-lens override at ``lenses.<lens>.necessity_classifier.mode``
|
|
1162
|
-
(default ``educate``).
|
|
1163
|
-
- ``invocation="user_explicit"`` → reads
|
|
1164
|
-
``necessity_classifier.user_explicit_mode`` with per-lens override
|
|
1165
|
-
at ``lenses.<lens>.necessity_classifier.user_explicit_mode``
|
|
1166
|
-
(default ``warn-only``).
|
|
1167
|
-
|
|
1168
|
-
Reads the synthesized dict shape produced by
|
|
1169
|
-
:func:`_synthesize_ai_council_block`, so both typed-config and
|
|
1170
|
-
legacy-settings paths are honoured.
|
|
1171
|
-
"""
|
|
1172
|
-
nc_block = ai_cfg.get("necessity_classifier") or {}
|
|
1173
|
-
enabled = bool(nc_block.get("enabled", True))
|
|
1174
|
-
lens_overrides = ai_cfg.get("lens_overrides") or {}
|
|
1175
|
-
if invocation == "user_explicit":
|
|
1176
|
-
global_mode = str(nc_block.get("user_explicit_mode", "warn-only"))
|
|
1177
|
-
overrides = (
|
|
1178
|
-
lens_overrides.get("necessity_classifier_user_explicit_mode") or {}
|
|
1179
|
-
)
|
|
1180
|
-
else:
|
|
1181
|
-
global_mode = str(nc_block.get("mode", "educate"))
|
|
1182
|
-
overrides = lens_overrides.get("necessity_classifier_mode") or {}
|
|
1183
|
-
return enabled, str(overrides.get(lens, global_mode))
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
def _provider_caps_snapshot(ai_cfg: dict[str, Any]) -> dict[str, dict[str, str]]:
|
|
1187
|
-
"""Return ``{provider: {mode, model}}`` for enabled members.
|
|
1188
|
-
|
|
1189
|
-
Step-8 D3 events-log snapshot. Captures only public capability
|
|
1190
|
-
metadata (no API keys, no prompt content) so the log line stays
|
|
1191
|
-
within the privacy floor. Disabled members are excluded.
|
|
1192
|
-
"""
|
|
1193
|
-
members = ai_cfg.get("members") or {}
|
|
1194
|
-
snapshot: dict[str, dict[str, str]] = {}
|
|
1195
|
-
if not isinstance(members, dict):
|
|
1196
|
-
return snapshot
|
|
1197
|
-
for name, cfg in members.items():
|
|
1198
|
-
if not isinstance(cfg, dict) or not cfg.get("enabled", True):
|
|
1199
|
-
continue
|
|
1200
|
-
snapshot[str(name)] = {
|
|
1201
|
-
"mode": str(cfg.get("mode", "")),
|
|
1202
|
-
"model": str(cfg.get("model", "")),
|
|
1203
|
-
}
|
|
1204
|
-
return snapshot
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
def _necessity_gate(
|
|
1208
|
-
*, prompt: str, lens: str, invocation: str, proceed_anyway: bool,
|
|
1209
|
-
ai_cfg: dict[str, Any], stdout=None, original_ask: str = "",
|
|
1210
|
-
) -> tuple[bool, int, ClassificationResult | None]:
|
|
1211
|
-
"""Apply the Phase-6 necessity classifier before any member fires.
|
|
1212
|
-
|
|
1213
|
-
Returns ``(proceed, exit_code, result)``. ``proceed=True`` means the
|
|
1214
|
-
dispatcher continues; ``proceed=False`` means the caller should
|
|
1215
|
-
return ``exit_code`` immediately. ``result`` carries the verdict for
|
|
1216
|
-
session.md provenance on the proceed path (None when classifier is
|
|
1217
|
-
disabled / off).
|
|
1218
|
-
|
|
1219
|
-
Step-8 D3: every non-disabled branch emits one
|
|
1220
|
-
:func:`append_event` line. ``original_ask`` is forwarded to the
|
|
1221
|
-
events log so the sha256[:12] hash anchors the line to the
|
|
1222
|
-
user-side question without leaking content. When the caller does
|
|
1223
|
-
not have an ``original_ask`` value, the prompt itself is hashed
|
|
1224
|
-
(legacy CLIs route through this path).
|
|
1225
|
-
"""
|
|
1226
|
-
out = stdout if stdout is not None else sys.stdout
|
|
1227
|
-
enabled, mode = _resolve_necessity_mode(ai_cfg, lens, invocation=invocation)
|
|
1228
|
-
if not enabled or mode == "off":
|
|
1229
|
-
return True, 0, None
|
|
1230
|
-
result = classify_necessity(prompt, lens=lens, invocation=invocation)
|
|
1231
|
-
caps = _provider_caps_snapshot(ai_cfg)
|
|
1232
|
-
hashed = original_ask or prompt
|
|
1233
|
-
|
|
1234
|
-
def _emit(action: str) -> None:
|
|
1235
|
-
append_event({
|
|
1236
|
-
"lens": lens, "invocation": invocation,
|
|
1237
|
-
"action": action, "verdict": result.verdict,
|
|
1238
|
-
"category": result.category,
|
|
1239
|
-
"mode": mode, "provider_caps": caps,
|
|
1240
|
-
"original_ask": hashed,
|
|
1241
|
-
})
|
|
1242
|
-
|
|
1243
|
-
if result.verdict != "unnecessary":
|
|
1244
|
-
if result.verdict == "borderline":
|
|
1245
|
-
out.write(
|
|
1246
|
-
f"council:necessity · borderline ({result.category}) · "
|
|
1247
|
-
f"{result.rationale}\n"
|
|
1248
|
-
)
|
|
1249
|
-
_emit("proceed")
|
|
1250
|
-
return True, 0, result
|
|
1251
|
-
# verdict == "unnecessary"
|
|
1252
|
-
if mode == "warn-only":
|
|
1253
|
-
# Annotated but never skips (step-8 D2). Applies to both
|
|
1254
|
-
# invocation tiers when the mode resolves to warn-only.
|
|
1255
|
-
out.write(
|
|
1256
|
-
f"council:necessity · warn-only ({result.category}) · "
|
|
1257
|
-
f"{result.rationale}\n"
|
|
1258
|
-
)
|
|
1259
|
-
_emit("proceed")
|
|
1260
|
-
return True, 0, result
|
|
1261
|
-
if mode == "block":
|
|
1262
|
-
out.write(
|
|
1263
|
-
f"council:necessity · skipped ({result.category}) · "
|
|
1264
|
-
f"{result.rationale}\n"
|
|
1265
|
-
f"council:necessity · mode=block — `--proceed-anyway` has "
|
|
1266
|
-
f"no effect on the block path.\n"
|
|
1267
|
-
)
|
|
1268
|
-
_emit("skip_necessity")
|
|
1269
|
-
return False, 0, result
|
|
1270
|
-
# mode == "educate"
|
|
1271
|
-
if invocation == "agent":
|
|
1272
|
-
out.write(
|
|
1273
|
-
f"council:necessity · skipped (agent, {result.category}) · "
|
|
1274
|
-
f"{result.rationale}\n"
|
|
1275
|
-
)
|
|
1276
|
-
_emit("skip_necessity")
|
|
1277
|
-
return False, 0, result
|
|
1278
|
-
# invocation == "user_explicit"
|
|
1279
|
-
if proceed_anyway:
|
|
1280
|
-
out.write(
|
|
1281
|
-
f"council:necessity · override (user_explicit + "
|
|
1282
|
-
f"--proceed-anyway, {result.category}) · "
|
|
1283
|
-
f"{result.rationale}\n"
|
|
1284
|
-
)
|
|
1285
|
-
_emit("proceed")
|
|
1286
|
-
return True, 0, result
|
|
1287
|
-
out.write(educate_message(result, lens) + "\n")
|
|
1288
|
-
_emit("skip_necessity")
|
|
1289
|
-
return False, 2, result
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
def _resolve_model_downgrade(
|
|
1293
|
-
ai_cfg: dict[str, Any], lens: str,
|
|
1294
|
-
) -> tuple[bool, bool]:
|
|
1295
|
-
"""Return ``(enabled, auto_apply)`` for the size-fit downgrade gate.
|
|
1296
|
-
|
|
1297
|
-
Per-lens override at ``lenses.<lens>.model_downgrade`` wins over the
|
|
1298
|
-
global ``model_downgrade`` block. Reads the synthesized dict shape
|
|
1299
|
-
from :func:`_synthesize_ai_council_block` so both typed-config and
|
|
1300
|
-
legacy paths are honoured.
|
|
1301
|
-
"""
|
|
1302
|
-
md_block = ai_cfg.get("model_downgrade") or {}
|
|
1303
|
-
enabled = bool(md_block.get("enabled", True))
|
|
1304
|
-
auto_apply = bool(md_block.get("auto_apply", False))
|
|
1305
|
-
overrides = (
|
|
1306
|
-
(ai_cfg.get("lens_overrides") or {}).get("model_downgrade") or {}
|
|
1307
|
-
)
|
|
1308
|
-
lens_override = overrides.get(lens) if isinstance(overrides, dict) else None
|
|
1309
|
-
if isinstance(lens_override, dict):
|
|
1310
|
-
enabled = bool(lens_override.get("enabled", enabled))
|
|
1311
|
-
auto_apply = bool(lens_override.get("auto_apply", auto_apply))
|
|
1312
|
-
return enabled, auto_apply
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
def _size_fit_gate(
|
|
1316
|
-
*, prompt: str, lens: str, members: list[ExternalAIClient],
|
|
1317
|
-
ai_cfg: dict[str, Any], stdout=None,
|
|
1318
|
-
) -> list[tuple[str, SizeFitVerdict, bool]]:
|
|
1319
|
-
"""Apply the Phase-7 size-fit classifier across enabled members.
|
|
1320
|
-
|
|
1321
|
-
Iterates every member with a configured ``model_ladder`` and runs
|
|
1322
|
-
:func:`classify_size_fit`. When ``auto_apply`` is true and a
|
|
1323
|
-
downgrade is suggested, the member's ``model`` attribute is rewritten
|
|
1324
|
-
in place; otherwise the suggestion is surfaced as a stdout notice
|
|
1325
|
-
and the original model stands. Members without a ladder are skipped
|
|
1326
|
-
silently.
|
|
1327
|
-
|
|
1328
|
-
Returns a list of ``(member_name, verdict, applied)`` tuples for
|
|
1329
|
-
session.md provenance. Never blocks the dispatch — Phase 7 is a
|
|
1330
|
-
suggestion gate, not a refusal gate.
|
|
1331
|
-
"""
|
|
1332
|
-
out = stdout if stdout is not None else sys.stdout
|
|
1333
|
-
enabled, auto_apply = _resolve_model_downgrade(ai_cfg, lens)
|
|
1334
|
-
decisions: list[tuple[str, SizeFitVerdict, bool]] = []
|
|
1335
|
-
if not enabled:
|
|
1336
|
-
return decisions
|
|
1337
|
-
members_cfg = ai_cfg.get("members") or {}
|
|
1338
|
-
for member in members:
|
|
1339
|
-
member_cfg = members_cfg.get(member.name) or {}
|
|
1340
|
-
ladder = member_cfg.get("model_ladder") or ()
|
|
1341
|
-
if not ladder:
|
|
1342
|
-
continue
|
|
1343
|
-
verdict = classify_size_fit(
|
|
1344
|
-
prompt, current_model=member.model, ladder=ladder, lens=lens,
|
|
1345
|
-
)
|
|
1346
|
-
applied = False
|
|
1347
|
-
if not verdict.fit and verdict.suggested_model:
|
|
1348
|
-
if auto_apply:
|
|
1349
|
-
out.write(
|
|
1350
|
-
f"council:size-fit · {member.name} · auto-downgrade "
|
|
1351
|
-
f"`{member.model}` → `{verdict.suggested_model}` · "
|
|
1352
|
-
f"{verdict.reason}\n"
|
|
1353
|
-
)
|
|
1354
|
-
member.model = verdict.suggested_model
|
|
1355
|
-
applied = True
|
|
1356
|
-
else:
|
|
1357
|
-
out.write(
|
|
1358
|
-
f"council:size-fit · {member.name} · "
|
|
1359
|
-
f"{downgrade_message(verdict, member.model)}\n"
|
|
1360
|
-
)
|
|
1361
|
-
decisions.append((member.name, verdict, applied))
|
|
1362
|
-
return decisions
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
def _resolve_cost_disclosure(
|
|
1366
|
-
ai_cfg: dict[str, Any], lens: str,
|
|
1367
|
-
) -> tuple[str, float, bool]:
|
|
1368
|
-
"""Return ``(mode, threshold_usd, show_per_member)`` for the lens.
|
|
1369
|
-
|
|
1370
|
-
Per-lens override at ``lenses.<lens>.cost_disclosure`` wins over the
|
|
1371
|
-
global ``debate.cost_disclosure`` block. The ``debate`` lens gets
|
|
1372
|
-
the debate-scoped defaults; other lenses default to ``off`` unless
|
|
1373
|
-
explicitly overridden (Phase 8 step 5 \u2014 cheap lenses are opt-in).
|
|
1374
|
-
"""
|
|
1375
|
-
debate_block = ai_cfg.get("debate") or {}
|
|
1376
|
-
debate_disc = debate_block.get("cost_disclosure") or {}
|
|
1377
|
-
if lens == "debate":
|
|
1378
|
-
mode = str(debate_disc.get("mode", "always"))
|
|
1379
|
-
threshold = float(debate_disc.get("threshold_usd", 1.00))
|
|
1380
|
-
show_per_member = bool(debate_disc.get("show_per_member", True))
|
|
1381
|
-
else:
|
|
1382
|
-
mode = "off"
|
|
1383
|
-
threshold = 1.00
|
|
1384
|
-
show_per_member = True
|
|
1385
|
-
overrides = (
|
|
1386
|
-
(ai_cfg.get("lens_overrides") or {}).get("cost_disclosure") or {}
|
|
1387
|
-
)
|
|
1388
|
-
lens_override = overrides.get(lens) if isinstance(overrides, dict) else None
|
|
1389
|
-
if isinstance(lens_override, dict):
|
|
1390
|
-
mode = str(lens_override.get("mode", mode))
|
|
1391
|
-
threshold = float(lens_override.get("threshold_usd", threshold))
|
|
1392
|
-
show_per_member = bool(lens_override.get("show_per_member", show_per_member))
|
|
1393
|
-
return mode, threshold, show_per_member
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
def _format_cost_disclosure(
|
|
1397
|
-
est: DebateCostEstimate, *, lens: str, show_per_member: bool,
|
|
1398
|
-
) -> str:
|
|
1399
|
-
"""Render the pre-flight disclosure block for stdout.
|
|
1400
|
-
|
|
1401
|
-
Mirrors the roadmap spec: total range across N members \u00d7 R rounds,
|
|
1402
|
-
optional per-member breakdown, and a subscription-member call-out
|
|
1403
|
-
for CLI / manual transports that don't sum into USD totals.
|
|
1404
|
-
"""
|
|
1405
|
-
lines = [
|
|
1406
|
-
f"council:{lens} \u00b7 cost-disclosure \u00b7 estimated "
|
|
1407
|
-
f"${est.low_usd:.4f} \u2013 ${est.high_usd:.4f} "
|
|
1408
|
-
f"(expected ${est.expected_usd:.4f}) across "
|
|
1409
|
-
f"{len(est.per_member)} billable members \u00d7 {est.rounds} rounds",
|
|
1410
|
-
]
|
|
1411
|
-
if show_per_member and est.per_member:
|
|
1412
|
-
lines.append(" per member:")
|
|
1413
|
-
for pm in est.per_member:
|
|
1414
|
-
lines.append(
|
|
1415
|
-
f" \u00b7 {pm['name']:<14} {pm['model']:<22} "
|
|
1416
|
-
f"${pm['low_usd']:.4f} \u2013 ${pm['high_usd']:.4f}",
|
|
1417
|
-
)
|
|
1418
|
-
if est.subscription_members:
|
|
1419
|
-
lines.append(" subscription (no USD spend):")
|
|
1420
|
-
for sm in est.subscription_members:
|
|
1421
|
-
label = sm.get("subscription_label") or sm.get("transport", "")
|
|
1422
|
-
lines.append(
|
|
1423
|
-
f" \u00b7 {sm['name']:<14} {sm['model']:<22} ({label})",
|
|
1424
|
-
)
|
|
1425
|
-
return "\n".join(lines) + "\n"
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
def _debate_refusal_cap(
|
|
1429
|
-
ai_cfg: dict[str, Any],
|
|
1430
|
-
) -> float:
|
|
1431
|
-
"""Resolve the hard refusal cap (``debate.max_cost_usd``).
|
|
1432
|
-
|
|
1433
|
-
Returns 0.0 when disabled. The cap is unconditional \u2014 no
|
|
1434
|
-
``--proceed-anyway`` override (the user must lower rounds, drop
|
|
1435
|
-
members, or raise the cap explicitly).
|
|
1436
|
-
"""
|
|
1437
|
-
debate_block = ai_cfg.get("debate") or {}
|
|
1438
|
-
return float(debate_block.get("max_cost_usd", 5.00) or 0.0)
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
def _emit_shadow_slo_banner() -> None:
|
|
1442
|
-
"""Pre-flight SLO banner for solo-dispatch invocations (step-9 P10).
|
|
1443
|
-
|
|
1444
|
-
Reads ``agents/runtime/council/shadow-log.jsonl`` and prints the 7-day rolling
|
|
1445
|
-
disagreement rate. ``OK``, ``WARN``, ``BREACH`` are all surfaced so the
|
|
1446
|
-
user can see when single-member quality is drifting. Never auto-flips
|
|
1447
|
-
back to full council \u2014 visibility-first, action-second (D10).
|
|
1448
|
-
"""
|
|
1449
|
-
try:
|
|
1450
|
-
from scripts.ai_council import shadow_dispatch as _sd
|
|
1451
|
-
rate, n = _sd.compute_disagreement_rate(_sd.SHADOW_LOG_PATH)
|
|
1452
|
-
if n == 0:
|
|
1453
|
-
return
|
|
1454
|
-
sys.stdout.write(_sd.slo_banner(rate, n) + "\n")
|
|
1455
|
-
except Exception: # noqa: BLE001 \u2014 banner must never break dispatch.
|
|
1456
|
-
return
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
def _apply_solo_dispatch(
|
|
1460
|
-
members: list[ExternalAIClient],
|
|
1461
|
-
) -> tuple[list[ExternalAIClient], str | None]:
|
|
1462
|
-
"""Filter ``members`` to a single solo-dispatch pick (step-9 P9).
|
|
1463
|
-
|
|
1464
|
-
Loads the routing chain from ``agents/settings/.ai-council.yml`` and asks
|
|
1465
|
-
:func:`select_solo_member` for the first chain entry whose member
|
|
1466
|
-
is runtime-present. The probe is conservative: a member counts as
|
|
1467
|
-
auth-valid iff ``build_members`` returned a runtime client for it
|
|
1468
|
-
\u2014 build_members has already filtered out missing binaries / bad
|
|
1469
|
-
keys via the ``skipped`` list. Deep CLI auth probes (e.g.
|
|
1470
|
-
``claude auth status``) are reserved for the shadow-mode path.
|
|
1471
|
-
|
|
1472
|
-
Returns ``(filtered_members, marker)``. ``marker`` is a one-line
|
|
1473
|
-
info banner the caller prints to stdout (``None`` when no banner
|
|
1474
|
-
is needed, e.g. config missing). Returns the unfiltered list when
|
|
1475
|
-
no solo member can be picked \u2014 caller never fails the decision.
|
|
1476
|
-
"""
|
|
1477
|
-
try:
|
|
1478
|
-
cfg = load_council_config(AI_COUNCIL_FILE)
|
|
1479
|
-
except (CouncilConfigError, FileNotFoundError):
|
|
1480
|
-
return members, None
|
|
1481
|
-
if not cfg.routing.solo_member_fallback_chain:
|
|
1482
|
-
return (
|
|
1483
|
-
members,
|
|
1484
|
-
"council:solo \u00b7 WARN \u00b7 --single requested but "
|
|
1485
|
-
"routing.solo_member_fallback_chain is empty \u2014 "
|
|
1486
|
-
"escalating to full council.",
|
|
1487
|
-
)
|
|
1488
|
-
runtime_names = {getattr(m, "name", "") for m in members}
|
|
1489
|
-
pick = select_solo_member(
|
|
1490
|
-
cfg.routing,
|
|
1491
|
-
cfg.members,
|
|
1492
|
-
auth_cache=AuthCache(),
|
|
1493
|
-
probe=lambda name, _t: name in runtime_names,
|
|
1494
|
-
)
|
|
1495
|
-
if pick is None:
|
|
1496
|
-
return (
|
|
1497
|
-
members,
|
|
1498
|
-
"council:solo \u00b7 WARN \u00b7 solo dispatch unavailable "
|
|
1499
|
-
"(no chain member runtime-present) \u2014 escalating to "
|
|
1500
|
-
"full council.",
|
|
1501
|
-
)
|
|
1502
|
-
filtered = [m for m in members if getattr(m, "name", "") == pick]
|
|
1503
|
-
if not filtered:
|
|
1504
|
-
# Defensive: ``pick`` came from runtime_names so this should
|
|
1505
|
-
# be unreachable. If we ever get here, escalate rather than
|
|
1506
|
-
# ship an empty council.
|
|
1507
|
-
return (
|
|
1508
|
-
members,
|
|
1509
|
-
"council:solo \u00b7 WARN \u00b7 selected member vanished "
|
|
1510
|
-
"between probe and filter \u2014 escalating to full council.",
|
|
1511
|
-
)
|
|
1512
|
-
return (
|
|
1513
|
-
filtered,
|
|
1514
|
-
f"council:solo \u00b7 dispatching to {pick} only "
|
|
1515
|
-
f"(routing.solo_member_fallback_chain).",
|
|
1516
|
-
)
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
def cmd_run(
|
|
1520
|
-
args: argparse.Namespace,
|
|
1521
|
-
*,
|
|
1522
|
-
settings: dict[str, Any] | None = None,
|
|
1523
|
-
members: list[ExternalAIClient] | None = None,
|
|
1524
|
-
table: PriceTable | None = None,
|
|
1525
|
-
) -> int:
|
|
1526
|
-
"""Estimate, then run the council. Requires --confirm to spend."""
|
|
1527
|
-
if settings is None:
|
|
1528
|
-
settings = load_settings()
|
|
1529
|
-
ai_cfg = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
|
|
1530
|
-
advisor_plans = _build_advisor_plans(ai_cfg, REPO_ROOT)
|
|
1531
|
-
explicit_overrides = _parse_model_overrides(getattr(args, "model", None))
|
|
1532
|
-
skipped: list[dict[str, Any]] = []
|
|
1533
|
-
if members is None:
|
|
1534
|
-
members = build_members(
|
|
1535
|
-
settings,
|
|
1536
|
-
invocation_mode=args.mode_override,
|
|
1537
|
-
model_overrides=_advisor_model_overrides(
|
|
1538
|
-
advisor_plans, explicit_overrides,
|
|
1539
|
-
),
|
|
1540
|
-
siblings_overrides=_parse_siblings_overrides(getattr(args, "siblings", None)),
|
|
1541
|
-
skipped=skipped,
|
|
1542
|
-
)
|
|
1543
|
-
if getattr(args, "single", False):
|
|
1544
|
-
members, solo_banner = _apply_solo_dispatch(members)
|
|
1545
|
-
if solo_banner:
|
|
1546
|
-
sys.stdout.write(solo_banner + "\n")
|
|
1547
|
-
_emit_shadow_slo_banner()
|
|
1548
|
-
if table is None:
|
|
1549
|
-
table = load_prices()
|
|
1550
|
-
question, artefact = build_question(
|
|
1551
|
-
input_path=Path(args.question), input_mode=args.input_mode,
|
|
1552
|
-
max_tokens=_resolve_max_tokens(args, ai_cfg),
|
|
1553
|
-
prompt_mode_override=getattr(args, "prompt_mode", None),
|
|
1554
|
-
)
|
|
1555
|
-
proceed, gate_exit, _necessity_result = _necessity_gate(
|
|
1556
|
-
prompt=question.user_prompt,
|
|
1557
|
-
lens=question.mode,
|
|
1558
|
-
invocation=getattr(args, "invocation", "agent"),
|
|
1559
|
-
proceed_anyway=getattr(args, "proceed_anyway", False),
|
|
1560
|
-
ai_cfg=ai_cfg,
|
|
1561
|
-
original_ask=getattr(args, "original_ask", "") or "",
|
|
1562
|
-
)
|
|
1563
|
-
if not proceed:
|
|
1564
|
-
return gate_exit
|
|
1565
|
-
_size_fit_gate(
|
|
1566
|
-
prompt=question.user_prompt,
|
|
1567
|
-
lens=question.mode,
|
|
1568
|
-
members=members,
|
|
1569
|
-
ai_cfg=ai_cfg,
|
|
1570
|
-
)
|
|
1571
|
-
project = detect_project_context(REPO_ROOT)
|
|
1572
|
-
billable = [m for m in members if getattr(m, "billable", True)]
|
|
1573
|
-
estimates = estimate(question, billable, table,
|
|
1574
|
-
project=project, original_ask=args.original_ask,
|
|
1575
|
-
advisor_plans=advisor_plans)
|
|
1576
|
-
extra_calls, extra_usd = _consensus_cost_delta(
|
|
1577
|
-
ai_cfg, question.mode, estimates, len(billable),
|
|
1578
|
-
)
|
|
1579
|
-
pr_extra_calls, pr_extra_usd = _peer_review_cost_delta(
|
|
1580
|
-
ai_cfg, args, estimates, len(billable),
|
|
1581
|
-
)
|
|
1582
|
-
sys.stdout.write(
|
|
1583
|
-
f"council:run · mode={question.mode} · members={len(members)} "
|
|
1584
|
-
f"(billable={len(billable)})\n"
|
|
1585
|
-
)
|
|
1586
|
-
advisor_summary = _format_advisor_summary(advisor_plans, billable)
|
|
1587
|
-
if advisor_summary:
|
|
1588
|
-
sys.stdout.write(advisor_summary + "\n")
|
|
1589
|
-
if skipped:
|
|
1590
|
-
sys.stdout.write(format_install_hints(skipped) + "\n")
|
|
1591
|
-
sys.stdout.write(
|
|
1592
|
-
format_estimate_table(
|
|
1593
|
-
billable, estimates,
|
|
1594
|
-
consensus_delta_usd=extra_usd,
|
|
1595
|
-
consensus_extra_calls=extra_calls,
|
|
1596
|
-
peer_review_delta_usd=pr_extra_usd,
|
|
1597
|
-
peer_review_extra_calls=pr_extra_calls,
|
|
1598
|
-
) + "\n"
|
|
1599
|
-
)
|
|
1600
|
-
|
|
1601
|
-
# Step-8 P1 — pre-run quota summary. After estimate / before
|
|
1602
|
-
# dispatch so the user sees the budget shape before --confirm.
|
|
1603
|
-
# Uncapped providers are omitted by ``quota_summary_line``; when
|
|
1604
|
-
# no CLI member has a configured cap the summary is empty and we
|
|
1605
|
-
# write nothing.
|
|
1606
|
-
cli_members = [m for m in members if isinstance(m, CliClient)]
|
|
1607
|
-
summary, warn_providers = quota_summary_line(cli_members)
|
|
1608
|
-
if summary:
|
|
1609
|
-
sys.stdout.write(summary + "\n")
|
|
1610
|
-
for prov in warn_providers:
|
|
1611
|
-
sys.stdout.write(f"council:quota · WARN · {prov} near limit\n")
|
|
1612
|
-
|
|
1613
|
-
# Phase 8 step 5 — opt-in cost disclosure for non-debate lenses.
|
|
1614
|
-
# Default mode is "off" for analysis / default (cheap enough that
|
|
1615
|
-
# the disclosure is friction); users opt in by setting
|
|
1616
|
-
# `lenses.<name>.cost_disclosure.mode` in agents/settings/.ai-council.yml.
|
|
1617
|
-
disc_mode, disc_threshold, disc_show = _resolve_cost_disclosure(
|
|
1618
|
-
ai_cfg, question.mode,
|
|
1619
|
-
)
|
|
1620
|
-
if disc_mode != "off":
|
|
1621
|
-
run_estimate = estimate_debate_cost(
|
|
1622
|
-
question, members, table,
|
|
1623
|
-
rounds=1, project=project,
|
|
1624
|
-
original_ask=args.original_ask,
|
|
1625
|
-
advisor_plans=advisor_plans,
|
|
1626
|
-
)
|
|
1627
|
-
if disc_mode == "always" or (
|
|
1628
|
-
disc_mode == "above_threshold"
|
|
1629
|
-
and run_estimate.expected_usd > disc_threshold
|
|
1630
|
-
):
|
|
1631
|
-
sys.stdout.write(
|
|
1632
|
-
_format_cost_disclosure(
|
|
1633
|
-
run_estimate, lens=question.mode,
|
|
1634
|
-
show_per_member=disc_show,
|
|
1635
|
-
)
|
|
1636
|
-
)
|
|
1637
|
-
|
|
1638
|
-
if not args.confirm:
|
|
1639
|
-
sys.stdout.write(
|
|
1640
|
-
"\nNo --confirm flag — estimate only. Re-run with --confirm to "
|
|
1641
|
-
"invoke the council and write the response.\n"
|
|
1642
|
-
)
|
|
1643
|
-
return 0
|
|
1644
|
-
|
|
1645
|
-
cost_cfg = ai_cfg.get("cost_budget") or {}
|
|
1646
|
-
budget = CostBudget(
|
|
1647
|
-
max_input_tokens=int(cost_cfg.get("max_input_tokens", 50_000)),
|
|
1648
|
-
max_output_tokens=int(cost_cfg.get("max_output_tokens", 20_000)),
|
|
1649
|
-
max_calls=int(cost_cfg.get("max_calls", 10)),
|
|
1650
|
-
max_total_usd=float(cost_cfg.get("max_total_usd", 0.0) or 0.0),
|
|
1651
|
-
)
|
|
1652
|
-
rounds = _resolve_rounds(args, ai_cfg)
|
|
1653
|
-
responses = consult(
|
|
1654
|
-
members, question, budget,
|
|
1655
|
-
table=table, project=project,
|
|
1656
|
-
original_ask=args.original_ask, rounds=rounds,
|
|
1657
|
-
advisor_plans=advisor_plans,
|
|
1658
|
-
)
|
|
1659
|
-
# Pipeline order (R4 verdict): deliberation → peer-review → consensus
|
|
1660
|
-
# → synthesis. Peer-review anonymises only deliberation outputs;
|
|
1661
|
-
# consensus-scoring runs on the de-anonymised findings.
|
|
1662
|
-
persona_labels = build_persona_labels(advisor_plans, billable)
|
|
1663
|
-
peer_review = _maybe_run_peer_review(
|
|
1664
|
-
ai_cfg, args, question, members, responses, budget, table, project,
|
|
1665
|
-
persona_labels=persona_labels,
|
|
1666
|
-
)
|
|
1667
|
-
consensus = _maybe_run_consensus(
|
|
1668
|
-
ai_cfg, question, members, responses, budget, table, project, args,
|
|
1669
|
-
)
|
|
1670
|
-
estimated_total = sum(e.total_usd for e in estimates)
|
|
1671
|
-
actual_total = 0.0
|
|
1672
|
-
all_responses: list[CouncilResponse] = list(responses)
|
|
1673
|
-
if peer_review is not None:
|
|
1674
|
-
all_responses.extend(peer_review.responses)
|
|
1675
|
-
if consensus is not None:
|
|
1676
|
-
all_responses.extend(consensus.extraction_responses)
|
|
1677
|
-
all_responses.extend(consensus.scoring_responses)
|
|
1678
|
-
for r in all_responses:
|
|
1679
|
-
if r.error:
|
|
1680
|
-
continue
|
|
1681
|
-
ce = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
|
|
1682
|
-
actual_total += ce.total_usd
|
|
1683
|
-
payload = {
|
|
1684
|
-
"schema_version": SCHEMA_VERSION,
|
|
1685
|
-
"mode": question.mode,
|
|
1686
|
-
"prompt_mode": getattr(args, "prompt_mode", None),
|
|
1687
|
-
"prose_synthesis": getattr(args, "prose_synthesis", None),
|
|
1688
|
-
"peer_review_enabled": _peer_review_active(ai_cfg, args),
|
|
1689
|
-
"artefact": artefact,
|
|
1690
|
-
"original_ask": args.original_ask,
|
|
1691
|
-
"members": [f"{m.name}/{m.model}" for m in members],
|
|
1692
|
-
"rounds": rounds,
|
|
1693
|
-
"cost_usd_estimated": round(estimated_total, 6),
|
|
1694
|
-
"cost_usd_actual": round(actual_total, 6),
|
|
1695
|
-
"responses": _serialise_responses(responses),
|
|
1696
|
-
}
|
|
1697
|
-
if peer_review is not None:
|
|
1698
|
-
payload["peer_review"] = _serialise_peer_review(peer_review)
|
|
1699
|
-
if consensus is not None:
|
|
1700
|
-
payload["consensus"] = _serialise_consensus(consensus)
|
|
1701
|
-
out_path = _validate_council_output_path(
|
|
1702
|
-
args.output, kind="responses", subcommand="run",
|
|
1703
|
-
)
|
|
1704
|
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1705
|
-
out_path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
|
1706
|
-
sys.stdout.write(
|
|
1707
|
-
f"\ncouncil:run · wrote {out_path} "
|
|
1708
|
-
f"(estimated ${estimated_total:.4f} / actual ${actual_total:.4f})\n"
|
|
1709
|
-
)
|
|
1710
|
-
replay_path = _maybe_write_decision_replay(
|
|
1711
|
-
ai_cfg=ai_cfg, lens=question.mode, out_path=out_path,
|
|
1712
|
-
consensus=consensus, deliberation=responses,
|
|
1713
|
-
original_ask=args.original_ask,
|
|
1714
|
-
)
|
|
1715
|
-
if replay_path is not None:
|
|
1716
|
-
sys.stdout.write(f"council:run · wrote {replay_path}\n")
|
|
1717
|
-
errors = [r for r in responses if r.error]
|
|
1718
|
-
return 1 if errors and len(errors) == len(responses) else 0
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
def _debate_round_filename(round_number: int) -> str:
|
|
1722
|
-
return f"debate-round-{round_number}.json"
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
def _write_debate_round(
|
|
1726
|
-
out_dir: Path,
|
|
1727
|
-
round_number: int,
|
|
1728
|
-
responses: list[CouncilResponse],
|
|
1729
|
-
*,
|
|
1730
|
-
question: CouncilQuestion,
|
|
1731
|
-
members: list[ExternalAIClient],
|
|
1732
|
-
artefact: str,
|
|
1733
|
-
original_ask: str,
|
|
1734
|
-
total_planned_rounds: int,
|
|
1735
|
-
table: PriceTable,
|
|
1736
|
-
prompt_mode: str | None,
|
|
1737
|
-
prose_synthesis: bool | None,
|
|
1738
|
-
) -> Path:
|
|
1739
|
-
"""Persist a single debate round as a self-contained JSON.
|
|
1740
|
-
|
|
1741
|
-
Each round file mirrors the ``cmd_run`` payload shape — re-rendering
|
|
1742
|
-
via ``council render <debate-round-N.json>`` works without special
|
|
1743
|
-
handling. Round-specific keys (``debate_round``, ``debate_total_rounds``)
|
|
1744
|
-
are additive so the renderer can ignore them safely.
|
|
1745
|
-
"""
|
|
1746
|
-
out_dir.mkdir(parents=True, exist_ok=True)
|
|
1747
|
-
actual_total = 0.0
|
|
1748
|
-
for r in responses:
|
|
1749
|
-
if r.error:
|
|
1750
|
-
continue
|
|
1751
|
-
ce = estimate_cost(r.provider, r.model, r.input_tokens, r.output_tokens, table)
|
|
1752
|
-
actual_total += ce.total_usd
|
|
1753
|
-
payload = {
|
|
1754
|
-
"schema_version": SCHEMA_VERSION,
|
|
1755
|
-
"mode": question.mode,
|
|
1756
|
-
"prompt_mode": prompt_mode,
|
|
1757
|
-
"prose_synthesis": prose_synthesis,
|
|
1758
|
-
"artefact": artefact,
|
|
1759
|
-
"original_ask": original_ask,
|
|
1760
|
-
"members": [f"{m.name}/{m.model}" for m in members],
|
|
1761
|
-
"debate_round": round_number,
|
|
1762
|
-
"debate_total_rounds": total_planned_rounds,
|
|
1763
|
-
"rounds": 1,
|
|
1764
|
-
"cost_usd_actual": round(actual_total, 6),
|
|
1765
|
-
"responses": _serialise_responses(responses),
|
|
1766
|
-
}
|
|
1767
|
-
out_path = out_dir / _debate_round_filename(round_number)
|
|
1768
|
-
out_path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
|
|
1769
|
-
return out_path
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
def _load_debate_seed(
|
|
1773
|
-
path: Path,
|
|
1774
|
-
expected_members: list[ExternalAIClient],
|
|
1775
|
-
) -> list[CouncilResponse]:
|
|
1776
|
-
"""Load `--continue-as-debate` seed: round-1 responses from a prior session.
|
|
1777
|
-
|
|
1778
|
-
The seed file must be the JSON written by ``cmd_run`` (or a prior
|
|
1779
|
-
debate round). Members + models must match the current invocation —
|
|
1780
|
-
a mismatch is a hard error per the Phase 7 contract, not a silent
|
|
1781
|
-
fallback. The host agent surfaces the mismatch and asks the user
|
|
1782
|
-
to either re-run with matching members or drop ``--continue-as-debate``.
|
|
1783
|
-
"""
|
|
1784
|
-
if not path.exists():
|
|
1785
|
-
raise FileNotFoundError(
|
|
1786
|
-
f"--continue-as-debate path not found: {path}"
|
|
1787
|
-
)
|
|
1788
|
-
payload = json.loads(path.read_text(encoding="utf-8"))
|
|
1789
|
-
source_members = list(payload.get("members") or [])
|
|
1790
|
-
expected_labels = [f"{m.name}/{m.model}" for m in expected_members]
|
|
1791
|
-
if source_members != expected_labels:
|
|
1792
|
-
raise CouncilDisabledError(
|
|
1793
|
-
f"--continue-as-debate member mismatch: source session has "
|
|
1794
|
-
f"{source_members!r}, current invocation has {expected_labels!r}. "
|
|
1795
|
-
f"Re-run with matching members or drop --continue-as-debate."
|
|
1796
|
-
)
|
|
1797
|
-
return _deserialise_responses(payload.get("responses") or [])
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
def _make_debate_continue_prompt(
|
|
1801
|
-
*, auto_continue: bool,
|
|
1802
|
-
stream: Any = None,
|
|
1803
|
-
) -> Any:
|
|
1804
|
-
"""Build the on_continue callback for `run_debate()`.
|
|
1805
|
-
|
|
1806
|
-
``--auto-continue`` returns ``None`` so the orchestrator skips the
|
|
1807
|
-
gate entirely (still subject to the hard-cap check). Interactive
|
|
1808
|
-
mode prints the checkpoint line and reads y/N from stdin.
|
|
1809
|
-
"""
|
|
1810
|
-
if auto_continue:
|
|
1811
|
-
return None
|
|
1812
|
-
out = stream or sys.stdout
|
|
1813
|
-
|
|
1814
|
-
def _prompt(checkpoint: DebateCheckpoint) -> bool:
|
|
1815
|
-
out.write(
|
|
1816
|
-
f"\ndebate:checkpoint round={checkpoint.completed_round}/"
|
|
1817
|
-
f"{checkpoint.total_planned_rounds} "
|
|
1818
|
-
f"cost_so_far=${checkpoint.cost_so_far_usd:.4f} "
|
|
1819
|
-
f"next_round_estimate=${checkpoint.next_round_estimate_usd:.4f} "
|
|
1820
|
-
f"— continue? [y/N]: "
|
|
1821
|
-
)
|
|
1822
|
-
out.flush()
|
|
1823
|
-
try:
|
|
1824
|
-
answer = sys.stdin.readline().strip().lower()
|
|
1825
|
-
except (EOFError, KeyboardInterrupt):
|
|
1826
|
-
return False
|
|
1827
|
-
return answer in {"y", "yes"}
|
|
1828
|
-
|
|
1829
|
-
return _prompt
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
def cmd_debate(
|
|
1833
|
-
args: argparse.Namespace,
|
|
1834
|
-
*,
|
|
1835
|
-
settings: dict[str, Any] | None = None,
|
|
1836
|
-
members: list[ExternalAIClient] | None = None,
|
|
1837
|
-
table: PriceTable | None = None,
|
|
1838
|
-
) -> int:
|
|
1839
|
-
"""Run a multi-round debate with progressive cost disclosure.
|
|
1840
|
-
|
|
1841
|
-
Phase 7 contract: each member produces an initial position in
|
|
1842
|
-
Round 1, then rebuts the strongest opposing position in subsequent
|
|
1843
|
-
rounds. The orchestrator pauses after each round and asks the user
|
|
1844
|
-
to continue (``--auto-continue`` bypasses the prompt). Round files
|
|
1845
|
-
are persisted incrementally so an interrupted debate leaves a
|
|
1846
|
-
recoverable trail.
|
|
1847
|
-
"""
|
|
1848
|
-
if settings is None:
|
|
1849
|
-
settings = load_settings()
|
|
1850
|
-
ai_cfg = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
|
|
1851
|
-
advisor_plans = _build_advisor_plans(ai_cfg, REPO_ROOT)
|
|
1852
|
-
explicit_overrides = _parse_model_overrides(getattr(args, "model", None))
|
|
1853
|
-
skipped: list[dict[str, Any]] = []
|
|
1854
|
-
if members is None:
|
|
1855
|
-
members = build_members(
|
|
1856
|
-
settings,
|
|
1857
|
-
invocation_mode=args.mode_override,
|
|
1858
|
-
model_overrides=_advisor_model_overrides(
|
|
1859
|
-
advisor_plans, explicit_overrides,
|
|
1860
|
-
),
|
|
1861
|
-
siblings_overrides=_parse_siblings_overrides(
|
|
1862
|
-
getattr(args, "siblings", None),
|
|
1863
|
-
),
|
|
1864
|
-
skipped=skipped,
|
|
1865
|
-
)
|
|
1866
|
-
if table is None:
|
|
1867
|
-
table = load_prices()
|
|
1868
|
-
question, artefact = build_question(
|
|
1869
|
-
input_path=Path(args.question), input_mode=args.input_mode,
|
|
1870
|
-
max_tokens=_resolve_max_tokens(args, ai_cfg),
|
|
1871
|
-
prompt_mode_override="debate",
|
|
1872
|
-
)
|
|
1873
|
-
proceed, gate_exit, _necessity_result = _necessity_gate(
|
|
1874
|
-
prompt=question.user_prompt,
|
|
1875
|
-
lens="debate",
|
|
1876
|
-
invocation=getattr(args, "invocation", "agent"),
|
|
1877
|
-
proceed_anyway=getattr(args, "proceed_anyway", False),
|
|
1878
|
-
ai_cfg=ai_cfg,
|
|
1879
|
-
original_ask=getattr(args, "original_ask", "") or "",
|
|
1880
|
-
)
|
|
1881
|
-
if not proceed:
|
|
1882
|
-
return gate_exit
|
|
1883
|
-
_size_fit_gate(
|
|
1884
|
-
prompt=question.user_prompt,
|
|
1885
|
-
lens="debate",
|
|
1886
|
-
members=members,
|
|
1887
|
-
ai_cfg=ai_cfg,
|
|
1888
|
-
)
|
|
1889
|
-
project = detect_project_context(REPO_ROOT)
|
|
1890
|
-
billable = [m for m in members if getattr(m, "billable", True)]
|
|
1891
|
-
|
|
1892
|
-
# Resolve round count: explicit --rounds wins; otherwise default 2.
|
|
1893
|
-
# Hard ceiling: ai_council.debate_max_rounds (Phase 0 reserved key).
|
|
1894
|
-
max_rounds_cap = int(ai_cfg.get("debate_max_rounds", 4))
|
|
1895
|
-
requested = (
|
|
1896
|
-
int(args.rounds) if getattr(args, "rounds", None) is not None else 2
|
|
1897
|
-
)
|
|
1898
|
-
if requested < 1:
|
|
1899
|
-
raise argparse.ArgumentTypeError(
|
|
1900
|
-
f"--rounds must be >= 1 (got {requested})"
|
|
1901
|
-
)
|
|
1902
|
-
if requested > max_rounds_cap:
|
|
1903
|
-
raise argparse.ArgumentTypeError(
|
|
1904
|
-
f"--rounds={requested} exceeds debate_max_rounds={max_rounds_cap}; "
|
|
1905
|
-
f"raise the cap in agents/settings/.ai-council.yml or lower --rounds."
|
|
1906
|
-
)
|
|
1907
|
-
rounds = requested
|
|
1908
|
-
|
|
1909
|
-
estimates = estimate(
|
|
1910
|
-
question, billable, table,
|
|
1911
|
-
project=project, original_ask=args.original_ask,
|
|
1912
|
-
advisor_plans=advisor_plans,
|
|
1913
|
-
)
|
|
1914
|
-
per_round_usd = sum(e.total_usd for e in estimates)
|
|
1915
|
-
projected_total = per_round_usd * rounds
|
|
1916
|
-
sys.stdout.write(
|
|
1917
|
-
f"council:debate · members={len(members)} (billable={len(billable)}) "
|
|
1918
|
-
f"· rounds={rounds} (cap={max_rounds_cap})\n"
|
|
1919
|
-
)
|
|
1920
|
-
advisor_summary = _format_advisor_summary(advisor_plans, billable)
|
|
1921
|
-
if advisor_summary:
|
|
1922
|
-
sys.stdout.write(advisor_summary + "\n")
|
|
1923
|
-
if skipped:
|
|
1924
|
-
sys.stdout.write(format_install_hints(skipped) + "\n")
|
|
1925
|
-
sys.stdout.write(
|
|
1926
|
-
format_estimate_table(billable, estimates) + "\n"
|
|
1927
|
-
)
|
|
1928
|
-
sys.stdout.write(
|
|
1929
|
-
f" × {rounds} rounds (worst case, before progressive disclosure)\n"
|
|
1930
|
-
f" PROJECTED TOTAL: ${projected_total:.4f}\n"
|
|
1931
|
-
)
|
|
1932
|
-
|
|
1933
|
-
# Phase 8 — pre-flight cost disclosure + hard refusal cap.
|
|
1934
|
-
debate_estimate = estimate_debate_cost(
|
|
1935
|
-
question, members, table,
|
|
1936
|
-
rounds=rounds, project=project,
|
|
1937
|
-
original_ask=args.original_ask,
|
|
1938
|
-
advisor_plans=advisor_plans,
|
|
1939
|
-
)
|
|
1940
|
-
disc_mode, disc_threshold, disc_show = _resolve_cost_disclosure(
|
|
1941
|
-
ai_cfg, "debate",
|
|
1942
|
-
)
|
|
1943
|
-
should_disclose = (
|
|
1944
|
-
disc_mode == "always"
|
|
1945
|
-
or (
|
|
1946
|
-
disc_mode == "above_threshold"
|
|
1947
|
-
and debate_estimate.expected_usd > disc_threshold
|
|
1948
|
-
)
|
|
1949
|
-
)
|
|
1950
|
-
if should_disclose:
|
|
1951
|
-
sys.stdout.write(
|
|
1952
|
-
_format_cost_disclosure(
|
|
1953
|
-
debate_estimate, lens="debate", show_per_member=disc_show,
|
|
1954
|
-
)
|
|
1955
|
-
)
|
|
1956
|
-
cap = _debate_refusal_cap(ai_cfg)
|
|
1957
|
-
if cap > 0 and debate_estimate.high_usd > cap:
|
|
1958
|
-
sys.stderr.write(
|
|
1959
|
-
f"❌ council:debate refused · high-end estimate "
|
|
1960
|
-
f"${debate_estimate.high_usd:.4f} exceeds "
|
|
1961
|
-
f"debate.max_cost_usd=${cap:.2f}. Lower --rounds, drop "
|
|
1962
|
-
f"members, or raise the cap in agents/settings/.ai-council.yml.\n"
|
|
1963
|
-
)
|
|
1964
|
-
return 4
|
|
1965
|
-
|
|
1966
|
-
if not args.confirm:
|
|
1967
|
-
sys.stdout.write(
|
|
1968
|
-
"\nNo --confirm flag — estimate only. Re-run with --confirm to "
|
|
1969
|
-
"start the debate.\n"
|
|
1970
|
-
)
|
|
1971
|
-
return 0
|
|
1972
|
-
|
|
1973
|
-
cost_cfg = ai_cfg.get("cost_budget") or {}
|
|
1974
|
-
budget = CostBudget(
|
|
1975
|
-
max_input_tokens=int(cost_cfg.get("max_input_tokens", 50_000)),
|
|
1976
|
-
max_output_tokens=int(cost_cfg.get("max_output_tokens", 20_000)),
|
|
1977
|
-
max_calls=int(cost_cfg.get("max_calls", 10)),
|
|
1978
|
-
max_total_usd=float(cost_cfg.get("max_total_usd", 0.0) or 0.0),
|
|
1979
|
-
)
|
|
1980
|
-
|
|
1981
|
-
out_dir = _validate_council_output_path(
|
|
1982
|
-
args.output, kind="responses", subcommand="debate",
|
|
1983
|
-
)
|
|
1984
|
-
seed: list[CouncilResponse] | None = None
|
|
1985
|
-
if getattr(args, "continue_as_debate", None):
|
|
1986
|
-
seed = _load_debate_seed(Path(args.continue_as_debate), billable)
|
|
1987
|
-
sys.stdout.write(
|
|
1988
|
-
f"council:debate · seeding round 1 from "
|
|
1989
|
-
f"{args.continue_as_debate} ({len(seed)} responses)\n"
|
|
1990
|
-
)
|
|
1991
|
-
|
|
1992
|
-
written: list[Path] = []
|
|
1993
|
-
|
|
1994
|
-
def _on_round_complete(round_number: int, results: list[CouncilResponse]) -> None:
|
|
1995
|
-
path = _write_debate_round(
|
|
1996
|
-
out_dir, round_number, results,
|
|
1997
|
-
question=question, members=members,
|
|
1998
|
-
artefact=artefact, original_ask=args.original_ask,
|
|
1999
|
-
total_planned_rounds=rounds, table=table,
|
|
2000
|
-
prompt_mode="debate",
|
|
2001
|
-
prose_synthesis=getattr(args, "prose_synthesis", None),
|
|
2002
|
-
)
|
|
2003
|
-
written.append(path)
|
|
2004
|
-
errors = [r for r in results if r.error]
|
|
2005
|
-
sys.stdout.write(
|
|
2006
|
-
f"council:debate · wrote {path} "
|
|
2007
|
-
f"({len(results) - len(errors)}/{len(results)} ok)\n"
|
|
2008
|
-
)
|
|
2009
|
-
|
|
2010
|
-
on_continue = _make_debate_continue_prompt(
|
|
2011
|
-
auto_continue=bool(getattr(args, "auto_continue", False)),
|
|
2012
|
-
)
|
|
2013
|
-
|
|
2014
|
-
try:
|
|
2015
|
-
all_rounds = run_debate(
|
|
2016
|
-
members, question,
|
|
2017
|
-
budget=budget, table=table, project=project,
|
|
2018
|
-
original_ask=args.original_ask,
|
|
2019
|
-
max_rounds=rounds,
|
|
2020
|
-
on_round_complete=_on_round_complete,
|
|
2021
|
-
on_continue=on_continue,
|
|
2022
|
-
advisor_plans=advisor_plans,
|
|
2023
|
-
seed_round_1=seed,
|
|
2024
|
-
)
|
|
2025
|
-
except DebateCapExceeded as exc:
|
|
2026
|
-
sys.stderr.write(
|
|
2027
|
-
f"❌ council:debate cap reached after round {exc.completed_round}: "
|
|
2028
|
-
f"{exc}\n"
|
|
2029
|
-
f"Partial debate persisted under {out_dir} "
|
|
2030
|
-
f"({len(written)} rounds).\n"
|
|
2031
|
-
)
|
|
2032
|
-
return 3
|
|
2033
|
-
|
|
2034
|
-
actual_total = 0.0
|
|
2035
|
-
for rnd in all_rounds:
|
|
2036
|
-
for r in rnd:
|
|
2037
|
-
if r.error:
|
|
2038
|
-
continue
|
|
2039
|
-
ce = estimate_cost(
|
|
2040
|
-
r.provider, r.model, r.input_tokens, r.output_tokens, table,
|
|
2041
|
-
)
|
|
2042
|
-
actual_total += ce.total_usd
|
|
2043
|
-
sys.stdout.write(
|
|
2044
|
-
f"\ncouncil:debate · {len(all_rounds)} round(s) complete · "
|
|
2045
|
-
f"actual ${actual_total:.4f} (cap projection ${projected_total:.4f})\n"
|
|
2046
|
-
)
|
|
2047
|
-
errors_last = [r for r in all_rounds[-1] if r.error] if all_rounds else []
|
|
2048
|
-
return 1 if errors_last and len(errors_last) == len(all_rounds[-1]) else 0
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
def cmd_render(args: argparse.Namespace) -> int:
|
|
2052
|
-
"""Re-render a saved responses JSON to the markdown report.
|
|
2053
|
-
|
|
2054
|
-
Lens resolution order: explicit ``--prompt-mode`` > ``prompt_mode``
|
|
2055
|
-
in the payload > ``mode`` in the payload > ``None`` (default decision
|
|
2056
|
-
template). R4 Q4 escape hatch ``--prose-synthesis`` overrides the
|
|
2057
|
-
table. ``--output`` writes to ``agents/runtime/council/sessions/`` (enforced);
|
|
2058
|
-
omit it for stdout.
|
|
2059
|
-
"""
|
|
2060
|
-
payload = json.loads(Path(args.responses).read_text(encoding="utf-8"))
|
|
2061
|
-
items = payload.get("responses") or []
|
|
2062
|
-
explicit = getattr(args, "prompt_mode", None)
|
|
2063
|
-
mode = explicit or payload.get("prompt_mode") or payload.get("mode")
|
|
2064
|
-
prose = getattr(args, "prose_synthesis", None)
|
|
2065
|
-
if prose is None:
|
|
2066
|
-
prose = payload.get("prose_synthesis")
|
|
2067
|
-
consensus = _deserialise_consensus(payload.get("consensus"))
|
|
2068
|
-
peer_review = _deserialise_peer_review(payload.get("peer_review"))
|
|
2069
|
-
body = render(
|
|
2070
|
-
_deserialise_responses(items),
|
|
2071
|
-
mode=mode,
|
|
2072
|
-
prose_synthesis=prose,
|
|
2073
|
-
consensus=consensus,
|
|
2074
|
-
peer_review=peer_review,
|
|
2075
|
-
)
|
|
2076
|
-
if getattr(args, "output", None):
|
|
2077
|
-
out_path = _validate_council_output_path(
|
|
2078
|
-
args.output, kind="sessions", subcommand="render",
|
|
2079
|
-
)
|
|
2080
|
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2081
|
-
out_path.write_text(body + "\n", encoding="utf-8")
|
|
2082
|
-
sys.stdout.write(f"council:render · wrote {out_path}\n")
|
|
2083
|
-
return 0
|
|
2084
|
-
sys.stdout.write(body + "\n")
|
|
2085
|
-
return 0
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
def _cmd_replay_low_impact_stats(args: argparse.Namespace) -> int:
|
|
2089
|
-
"""Summarise the session's ``low-impact-resolutions.md`` (Phase 11).
|
|
2090
|
-
|
|
2091
|
-
The log file lives next to the ``responses`` JSON. Missing or empty
|
|
2092
|
-
log → prints an explicit "no entries" line and returns 0 (a session
|
|
2093
|
-
with no low-impact resolutions is not an error).
|
|
2094
|
-
"""
|
|
2095
|
-
from scripts.ai_council.low_impact import ( # noqa: WPS433 — local import
|
|
2096
|
-
parse_low_impact_log,
|
|
2097
|
-
render_low_impact_stats,
|
|
2098
|
-
)
|
|
2099
|
-
|
|
2100
|
-
responses_path = Path(args.responses)
|
|
2101
|
-
log_path = responses_path.parent / "low-impact-resolutions.md"
|
|
2102
|
-
if not log_path.exists():
|
|
2103
|
-
sys.stdout.write(
|
|
2104
|
-
"council:replay · no low-impact-resolutions.md alongside "
|
|
2105
|
-
f"{responses_path} — session had no fast-path entries.\n",
|
|
2106
|
-
)
|
|
2107
|
-
return 0
|
|
2108
|
-
body = log_path.read_text(encoding="utf-8")
|
|
2109
|
-
stats = parse_low_impact_log(body)
|
|
2110
|
-
out = render_low_impact_stats(stats)
|
|
2111
|
-
if getattr(args, "output", None):
|
|
2112
|
-
target = _validate_council_output_path(
|
|
2113
|
-
args.output, kind="sessions", subcommand="replay",
|
|
2114
|
-
)
|
|
2115
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
2116
|
-
target.write_text(out, encoding="utf-8")
|
|
2117
|
-
sys.stdout.write(f"council:replay · wrote {target}\n")
|
|
2118
|
-
return 0
|
|
2119
|
-
sys.stdout.write(out)
|
|
2120
|
-
return 0
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
def cmd_replay(args: argparse.Namespace) -> int:
|
|
2124
|
-
"""Re-render the ``decision-replay.md`` audit trail (Phase 9).
|
|
2125
|
-
|
|
2126
|
-
Reads a saved ``council:run`` JSON payload, rebuilds the consensus
|
|
2127
|
-
bundle, and emits the replay markdown to stdout (default) or to
|
|
2128
|
-
``--output``. Pure re-projection — no model calls. Returns 2 when
|
|
2129
|
-
the payload lacks consensus data (Phase 9 prerequisite).
|
|
2130
|
-
|
|
2131
|
-
When ``--low-impact-stats`` is set, the consensus replay is skipped
|
|
2132
|
-
and the session's ``low-impact-resolutions.md`` (Phase 11) is
|
|
2133
|
-
summarised instead — count, status breakdown, members used, cost.
|
|
2134
|
-
"""
|
|
2135
|
-
if getattr(args, "low_impact_stats", False):
|
|
2136
|
-
return _cmd_replay_low_impact_stats(args)
|
|
2137
|
-
payload = json.loads(Path(args.responses).read_text(encoding="utf-8"))
|
|
2138
|
-
consensus = _deserialise_consensus(payload.get("consensus"))
|
|
2139
|
-
if consensus is None:
|
|
2140
|
-
sys.stderr.write(
|
|
2141
|
-
"❌ council:replay: payload has no `consensus` block — "
|
|
2142
|
-
"rerun with consensus_scoring enabled for this lens.\n"
|
|
2143
|
-
)
|
|
2144
|
-
return 2
|
|
2145
|
-
deliberation = _deserialise_responses(payload.get("responses") or [])
|
|
2146
|
-
include_args = (
|
|
2147
|
-
bool(args.include_member_arguments)
|
|
2148
|
-
if args.include_member_arguments is not None
|
|
2149
|
-
else True
|
|
2150
|
-
)
|
|
2151
|
-
body = render_decision_replay(
|
|
2152
|
-
DecisionReplayInputs(
|
|
2153
|
-
findings=list(consensus.findings),
|
|
2154
|
-
scores=list(consensus.scores),
|
|
2155
|
-
metadata=dict(consensus.metadata),
|
|
2156
|
-
deliberation=deliberation,
|
|
2157
|
-
original_ask=str(payload.get("original_ask", "")),
|
|
2158
|
-
include_member_arguments=include_args,
|
|
2159
|
-
),
|
|
2160
|
-
)
|
|
2161
|
-
if getattr(args, "output", None):
|
|
2162
|
-
out_path = _validate_council_output_path(
|
|
2163
|
-
args.output, kind="sessions", subcommand="replay",
|
|
2164
|
-
)
|
|
2165
|
-
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2166
|
-
out_path.write_text(body, encoding="utf-8")
|
|
2167
|
-
sys.stdout.write(f"council:replay · wrote {out_path}\n")
|
|
2168
|
-
else:
|
|
2169
|
-
sys.stdout.write(body)
|
|
2170
|
-
return 0
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
# ── argparse + main ─────────────────────────────────────────────────
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
def _parse_model_overrides(items: list[str] | None) -> dict[str, str]:
|
|
2177
|
-
"""Parse repeated `--model name=model-id` flags into a dict.
|
|
2178
|
-
|
|
2179
|
-
Empty/None list → empty dict (no override). Bad shape raises
|
|
2180
|
-
`argparse.ArgumentTypeError` so the CLI surfaces the error.
|
|
2181
|
-
"""
|
|
2182
|
-
out: dict[str, str] = {}
|
|
2183
|
-
for raw in items or []:
|
|
2184
|
-
if "=" not in raw:
|
|
2185
|
-
raise argparse.ArgumentTypeError(
|
|
2186
|
-
f"--model expects '<member>=<model-id>', got {raw!r}."
|
|
2187
|
-
)
|
|
2188
|
-
name, model = raw.split("=", 1)
|
|
2189
|
-
name, model = name.strip(), model.strip()
|
|
2190
|
-
if not name or not model:
|
|
2191
|
-
raise argparse.ArgumentTypeError(
|
|
2192
|
-
f"--model member and model-id must both be non-empty: {raw!r}."
|
|
2193
|
-
)
|
|
2194
|
-
out[name] = model
|
|
2195
|
-
return out
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
def _parse_siblings_overrides(items: list[str] | None) -> dict[str, list[str]]:
|
|
2199
|
-
"""Parse repeated `--siblings name=model1,model2[,...]` flags.
|
|
2200
|
-
|
|
2201
|
-
Requires ≥ 2 distinct, non-empty models per provider — sibling
|
|
2202
|
-
mode without diversity has no purpose. Repeating the same provider
|
|
2203
|
-
flag is rejected as ambiguous.
|
|
2204
|
-
"""
|
|
2205
|
-
out: dict[str, list[str]] = {}
|
|
2206
|
-
for raw in items or []:
|
|
2207
|
-
if "=" not in raw:
|
|
2208
|
-
raise argparse.ArgumentTypeError(
|
|
2209
|
-
f"--siblings expects '<member>=<model1>,<model2>[,...]', got {raw!r}."
|
|
2210
|
-
)
|
|
2211
|
-
name, models_csv = raw.split("=", 1)
|
|
2212
|
-
name = name.strip()
|
|
2213
|
-
models = [m.strip() for m in models_csv.split(",") if m.strip()]
|
|
2214
|
-
if not name or not models:
|
|
2215
|
-
raise argparse.ArgumentTypeError(
|
|
2216
|
-
f"--siblings member and model list must both be non-empty: {raw!r}."
|
|
2217
|
-
)
|
|
2218
|
-
if len(set(models)) < 2:
|
|
2219
|
-
raise argparse.ArgumentTypeError(
|
|
2220
|
-
f"--siblings requires ≥ 2 distinct models for {name!r}, got {models!r}."
|
|
2221
|
-
)
|
|
2222
|
-
if name in out:
|
|
2223
|
-
raise argparse.ArgumentTypeError(
|
|
2224
|
-
f"--siblings repeated for member {name!r}; combine into one flag."
|
|
2225
|
-
)
|
|
2226
|
-
out[name] = models
|
|
2227
|
-
return out
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
def _add_common_input_args(p: argparse.ArgumentParser) -> None:
|
|
2231
|
-
p.add_argument("question", type=str,
|
|
2232
|
-
help="Path to the question file (text or roadmap).")
|
|
2233
|
-
p.add_argument("--input-mode", choices=["prompt", "roadmap"],
|
|
2234
|
-
default="prompt",
|
|
2235
|
-
help="How to bundle the file (default: prompt).")
|
|
2236
|
-
p.add_argument("--prompt-mode",
|
|
2237
|
-
choices=["pr", "design", "optimize", "analysis"],
|
|
2238
|
-
default=None, dest="prompt_mode",
|
|
2239
|
-
help="Lens-override for the system-prompt addendum. "
|
|
2240
|
-
"The bundle shape stays as --input-mode; only "
|
|
2241
|
-
"the per-mode neutrality addendum is swapped "
|
|
2242
|
-
"(see scripts/ai_council/prompts.py _MODE_TABLE). "
|
|
2243
|
-
"Routed by the /council pr|design|optimize|"
|
|
2244
|
-
"analysis wrappers.")
|
|
2245
|
-
p.add_argument("--max-tokens", type=int, default=None,
|
|
2246
|
-
help="Per-member output budget. Default reads "
|
|
2247
|
-
"ai_council.max_output_tokens from .agent-settings.yml "
|
|
2248
|
-
"(2048 if unset). 0 = unlimited (widened to the safe "
|
|
2249
|
-
"provider ceiling before the SDK call).")
|
|
2250
|
-
p.add_argument("--mode-override", choices=["api", "manual"], default=None,
|
|
2251
|
-
help="Override every member's transport mode.")
|
|
2252
|
-
p.add_argument("--model", action="append", default=None, dest="model",
|
|
2253
|
-
metavar="MEMBER=MODEL_ID",
|
|
2254
|
-
help="Per-invocation model override, e.g. "
|
|
2255
|
-
"--model anthropic=claude-sonnet-4-5. Repeatable. "
|
|
2256
|
-
"Wins over `ai_council.members.<name>.model` in "
|
|
2257
|
-
".agent-settings.yml; the settings file is not "
|
|
2258
|
-
"modified.")
|
|
2259
|
-
p.add_argument("--siblings", action="append", default=None, dest="siblings",
|
|
2260
|
-
metavar="MEMBER=MODEL1,MODEL2[,...]",
|
|
2261
|
-
help="Fan one provider out to ≥ 2 sibling models in a "
|
|
2262
|
-
"single run, e.g. --siblings anthropic=claude-sonnet-4-5,"
|
|
2263
|
-
"claude-opus-4-1. Each model becomes its own billable "
|
|
2264
|
-
"member with independent cost tracking. Mutually "
|
|
2265
|
-
"exclusive with --model for the same provider; "
|
|
2266
|
-
"requires the provider to be enabled with mode=api. "
|
|
2267
|
-
"Single-provider degraded-run strategy per ai-council "
|
|
2268
|
-
"skill.")
|
|
2269
|
-
p.add_argument("--original-ask", default="",
|
|
2270
|
-
help="The user's framing sentence (flows into handoff).")
|
|
2271
|
-
p.add_argument("--peer-review", dest="peer_review", action="store_true",
|
|
2272
|
-
default=False,
|
|
2273
|
-
help="Run an anonymous peer-review pass after the main "
|
|
2274
|
-
"deliberation. Each member critiques the others' "
|
|
2275
|
-
"(anonymised) responses for blind spots before "
|
|
2276
|
-
"synthesis. Adds N extra API calls. Opt-in per the "
|
|
2277
|
-
"R2 verdict; also accepts ai_council.peer_review."
|
|
2278
|
-
"enabled: true in agents/settings/.ai-council.yml.")
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
def cmd_shadow_report(args: argparse.Namespace) -> int:
|
|
2282
|
-
"""Print the 7-day rolling disagreement rate + SLO status (step-9 P10)."""
|
|
2283
|
-
from pathlib import Path as _Path
|
|
2284
|
-
|
|
2285
|
-
from scripts.ai_council import shadow_dispatch as _sd
|
|
2286
|
-
|
|
2287
|
-
log_path = _Path(args.log) if args.log else _sd.SHADOW_LOG_PATH
|
|
2288
|
-
rate, n = _sd.compute_disagreement_rate(
|
|
2289
|
-
log_path, window_days=int(args.window_days)
|
|
2290
|
-
)
|
|
2291
|
-
print(_sd.slo_banner(rate, n))
|
|
2292
|
-
return 0
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
def cmd_quota(
|
|
2296
|
-
args: argparse.Namespace,
|
|
2297
|
-
*,
|
|
2298
|
-
settings: dict[str, Any] | None = None,
|
|
2299
|
-
) -> int:
|
|
2300
|
-
"""Dump today's CLI-quota state (step-8 P1, D1).
|
|
2301
|
-
|
|
2302
|
-
Reads ``~/.event4u/agent-config/cli-calls.json`` plus the configured
|
|
2303
|
-
caps from ``.agent-settings.yml`` and prints one line per provider
|
|
2304
|
-
that has a configured ``max_calls_per_day``. ``--reset <provider>``
|
|
2305
|
-
(gated behind ``--confirm``) clears the counter for that provider.
|
|
2306
|
-
"""
|
|
2307
|
-
s = settings if settings is not None else load_settings()
|
|
2308
|
-
ai_cfg = (s.get("ai_council") or {}) if isinstance(s, dict) else {}
|
|
2309
|
-
cli_budget_cfg = (
|
|
2310
|
-
(ai_cfg.get("cli_call_budget") or {}) if isinstance(ai_cfg, dict) else {}
|
|
2311
|
-
)
|
|
2312
|
-
caps = (
|
|
2313
|
-
(cli_budget_cfg.get("max_calls_per_day") or {})
|
|
2314
|
-
if isinstance(cli_budget_cfg, dict)
|
|
2315
|
-
else {}
|
|
2316
|
-
)
|
|
2317
|
-
warn_at = (
|
|
2318
|
-
float(cli_budget_cfg.get("warn_at", 0.8))
|
|
2319
|
-
if isinstance(cli_budget_cfg, dict)
|
|
2320
|
-
else 0.8
|
|
2321
|
-
)
|
|
2322
|
-
|
|
2323
|
-
if getattr(args, "reset", None):
|
|
2324
|
-
provider = args.reset
|
|
2325
|
-
if not getattr(args, "confirm", False):
|
|
2326
|
-
sys.stderr.write(
|
|
2327
|
-
f"❌ council:quota: --reset {provider} requires --confirm.\n"
|
|
2328
|
-
)
|
|
2329
|
-
return 2
|
|
2330
|
-
reset_cli_call_counts(provider=provider)
|
|
2331
|
-
sys.stdout.write(f"council:quota · reset · {provider}\n")
|
|
2332
|
-
return 0
|
|
2333
|
-
|
|
2334
|
-
counts = load_cli_call_counts()
|
|
2335
|
-
if not caps:
|
|
2336
|
-
sys.stdout.write(
|
|
2337
|
-
"council:quota · no providers have a configured "
|
|
2338
|
-
"cli_call_budget.max_calls_per_day cap.\n"
|
|
2339
|
-
)
|
|
2340
|
-
return 0
|
|
2341
|
-
for provider in sorted(caps):
|
|
2342
|
-
limit = int(caps[provider])
|
|
2343
|
-
used = int(counts.get(provider, 0))
|
|
2344
|
-
ratio = used / limit if limit > 0 else 0.0
|
|
2345
|
-
status = "ok"
|
|
2346
|
-
if used >= limit:
|
|
2347
|
-
status = "exhausted"
|
|
2348
|
-
elif ratio >= warn_at:
|
|
2349
|
-
status = "warn"
|
|
2350
|
-
sys.stdout.write(
|
|
2351
|
-
f"council:quota · {provider} · {used}/{limit} · {status}\n"
|
|
2352
|
-
)
|
|
2353
|
-
return 0
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
def build_parser() -> argparse.ArgumentParser:
|
|
2357
|
-
parser = argparse.ArgumentParser(
|
|
2358
|
-
prog="agent-config council",
|
|
2359
|
-
description="Non-interactive council orchestration.",
|
|
2360
|
-
)
|
|
2361
|
-
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
2362
|
-
|
|
2363
|
-
p_est = sub.add_parser("estimate", help="Pre-call cost preview (no spend).")
|
|
2364
|
-
_add_common_input_args(p_est)
|
|
2365
|
-
p_est.add_argument("--debate", action="store_true", default=False,
|
|
2366
|
-
help="Render the round-by-round projection for a "
|
|
2367
|
-
"debate run (one call per member per round). "
|
|
2368
|
-
"Progressive disclosure may stop the debate "
|
|
2369
|
-
"early — this is an upper bound.")
|
|
2370
|
-
p_est.add_argument("--rounds", type=int, default=None,
|
|
2371
|
-
help="Debate round count for --debate. Defaults to "
|
|
2372
|
-
"ai_council.min_rounds (typically 2); capped "
|
|
2373
|
-
"at ai_council.debate_max_rounds (typically 4).")
|
|
2374
|
-
|
|
2375
|
-
p_run = sub.add_parser("run", help="Run the council; --confirm required to spend.")
|
|
2376
|
-
_add_common_input_args(p_run)
|
|
2377
|
-
p_run.add_argument("--output", required=True,
|
|
2378
|
-
help="Path to write the responses JSON.")
|
|
2379
|
-
p_run.add_argument("--confirm", action="store_true",
|
|
2380
|
-
help="Required to actually invoke the council.")
|
|
2381
|
-
p_run.add_argument("--rounds", type=int, default=None,
|
|
2382
|
-
help="Number of debate rounds (1-3). Explicit override; "
|
|
2383
|
-
"wins over --depth. Defaults to ai_council.min_rounds "
|
|
2384
|
-
"in .agent-settings.yml (or 2 if unset).")
|
|
2385
|
-
p_run.add_argument("--depth", choices=["standard", "deep"], default="standard",
|
|
2386
|
-
help="Reasoning-depth tier. 'deep' floors rounds at "
|
|
2387
|
-
"ai_council.deep_min_rounds (max'd with min_rounds) "
|
|
2388
|
-
"for architecture, refactoring, or bug-diagnosis "
|
|
2389
|
-
"artefacts. Set by the host agent when the consuming "
|
|
2390
|
-
"rule/skill/command declares council_depth: deep. "
|
|
2391
|
-
"Overridden by explicit --rounds.")
|
|
2392
|
-
p_run.add_argument("--invocation", choices=["agent", "user_explicit"],
|
|
2393
|
-
default="agent",
|
|
2394
|
-
help="Source signal for the necessity classifier "
|
|
2395
|
-
"(Phase 6). 'agent' = autonomous (default; silent "
|
|
2396
|
-
"skip when unnecessary). 'user_explicit' = manual "
|
|
2397
|
-
"user invocation (educate path when unnecessary, "
|
|
2398
|
-
"requires --proceed-anyway to override).")
|
|
2399
|
-
p_run.add_argument("--proceed-anyway", action="store_true",
|
|
2400
|
-
dest="proceed_anyway", default=False,
|
|
2401
|
-
help="Override the necessity-classifier skip / educate "
|
|
2402
|
-
"verdict for this invocation (Phase 6). Has no "
|
|
2403
|
-
"effect when the classifier verdict is "
|
|
2404
|
-
"`necessary` or `borderline`.")
|
|
2405
|
-
p_run.add_argument("--single", action="store_true", default=False,
|
|
2406
|
-
help="Dispatch to a single member from "
|
|
2407
|
-
"routing.solo_member_fallback_chain (step-9 P9). "
|
|
2408
|
-
"Falls back to the full council when the chain is "
|
|
2409
|
-
"empty or no chain member is runtime-present. "
|
|
2410
|
-
"Overridden by env "
|
|
2411
|
-
"AGENT_CONFIG_FORCE_FULL_COUNCIL=1.")
|
|
2412
|
-
_add_prose_synthesis_arg(p_run)
|
|
2413
|
-
|
|
2414
|
-
p_deb = sub.add_parser(
|
|
2415
|
-
"debate",
|
|
2416
|
-
help="Multi-round debate with progressive cost disclosure (Phase 7).",
|
|
2417
|
-
)
|
|
2418
|
-
_add_common_input_args(p_deb)
|
|
2419
|
-
p_deb.add_argument("--output", required=True,
|
|
2420
|
-
help="Directory to write debate-round-N.json files.")
|
|
2421
|
-
p_deb.add_argument("--confirm", action="store_true",
|
|
2422
|
-
help="Required to actually start the debate.")
|
|
2423
|
-
p_deb.add_argument("--rounds", type=int, default=None,
|
|
2424
|
-
help="Number of debate rounds (default 2). Capped by "
|
|
2425
|
-
"ai_council.debate_max_rounds in agents/settings/.ai-council.yml.")
|
|
2426
|
-
p_deb.add_argument("--auto-continue", action="store_true",
|
|
2427
|
-
default=False, dest="auto_continue",
|
|
2428
|
-
help="Skip the between-round y/N prompt. The hard cap "
|
|
2429
|
-
"against cost_budget.max_total_usd still applies.")
|
|
2430
|
-
p_deb.add_argument("--continue-as-debate", default=None,
|
|
2431
|
-
dest="continue_as_debate", metavar="PATH",
|
|
2432
|
-
help="Seed round 1 from an existing council session "
|
|
2433
|
-
"JSON. Members + models must match the current "
|
|
2434
|
-
"invocation.")
|
|
2435
|
-
p_deb.add_argument("--invocation", choices=["agent", "user_explicit"],
|
|
2436
|
-
default="agent",
|
|
2437
|
-
help="Source signal for the necessity classifier "
|
|
2438
|
-
"(Phase 6). 'agent' = autonomous (default; silent "
|
|
2439
|
-
"skip when unnecessary). 'user_explicit' = manual "
|
|
2440
|
-
"user invocation (educate path when unnecessary, "
|
|
2441
|
-
"requires --proceed-anyway to override).")
|
|
2442
|
-
p_deb.add_argument("--proceed-anyway", action="store_true",
|
|
2443
|
-
dest="proceed_anyway", default=False,
|
|
2444
|
-
help="Override the necessity-classifier skip / educate "
|
|
2445
|
-
"verdict for this invocation (Phase 6). Has no "
|
|
2446
|
-
"effect when the classifier verdict is "
|
|
2447
|
-
"`necessary` or `borderline`.")
|
|
2448
|
-
_add_prose_synthesis_arg(p_deb)
|
|
2449
|
-
|
|
2450
|
-
p_ren = sub.add_parser("render", help="Re-render a saved responses JSON.")
|
|
2451
|
-
p_ren.add_argument("responses",
|
|
2452
|
-
help="Path to the JSON written by `council run`.")
|
|
2453
|
-
p_ren.add_argument("--prompt-mode",
|
|
2454
|
-
choices=["default", "pr", "design", "optimize", "analysis",
|
|
2455
|
-
"prompt", "roadmap", "diff", "files"],
|
|
2456
|
-
default=None, dest="prompt_mode",
|
|
2457
|
-
help="Override the synthesis-template lens. Defaults "
|
|
2458
|
-
"to the `mode` recorded in the responses JSON.")
|
|
2459
|
-
p_ren.add_argument("--output", default=None,
|
|
2460
|
-
help="Write the rendered markdown to a file under "
|
|
2461
|
-
"agents/runtime/council/sessions/ (enforced). Omit for "
|
|
2462
|
-
"stdout. Prefer this over shell redirects so "
|
|
2463
|
-
"the canonical-path check fires at write-time.")
|
|
2464
|
-
_add_prose_synthesis_arg(p_ren)
|
|
2465
|
-
|
|
2466
|
-
p_rep = sub.add_parser(
|
|
2467
|
-
"replay",
|
|
2468
|
-
help="Re-render decision-replay.md from a saved responses JSON (Phase 9).",
|
|
2469
|
-
)
|
|
2470
|
-
p_rep.add_argument("responses",
|
|
2471
|
-
help="Path to the JSON written by `council run`.")
|
|
2472
|
-
p_rep.add_argument("--output", default=None,
|
|
2473
|
-
help="Optional file to write the replay markdown. "
|
|
2474
|
-
"Defaults to stdout.")
|
|
2475
|
-
rep_group = p_rep.add_mutually_exclusive_group()
|
|
2476
|
-
rep_group.add_argument("--redact-member-arguments",
|
|
2477
|
-
dest="include_member_arguments",
|
|
2478
|
-
action="store_const", const=False, default=None,
|
|
2479
|
-
help="Emit the redacted view (consensus + dissent "
|
|
2480
|
-
"counts only, no per-member arguments).")
|
|
2481
|
-
rep_group.add_argument("--include-member-arguments",
|
|
2482
|
-
dest="include_member_arguments",
|
|
2483
|
-
action="store_const", const=True,
|
|
2484
|
-
help="Include per-member arguments (default).")
|
|
2485
|
-
p_rep.add_argument("--low-impact-stats", action="store_true", default=False,
|
|
2486
|
-
help="Skip the decision replay and print a summary of "
|
|
2487
|
-
"low-impact fast-path resolutions for the session "
|
|
2488
|
-
"(parses `low-impact-resolutions.md` alongside the "
|
|
2489
|
-
"responses JSON).")
|
|
2490
|
-
|
|
2491
|
-
p_quo = sub.add_parser(
|
|
2492
|
-
"quota",
|
|
2493
|
-
help="Dump today's CLI-quota state and configured caps (step-8 P1).",
|
|
2494
|
-
)
|
|
2495
|
-
p_quo.add_argument("--reset", default=None, metavar="PROVIDER",
|
|
2496
|
-
help="Reset today's counter for one provider. "
|
|
2497
|
-
"Requires --confirm.")
|
|
2498
|
-
p_quo.add_argument("--confirm", action="store_true", default=False,
|
|
2499
|
-
help="Confirm a mutating --reset operation.")
|
|
2500
|
-
|
|
2501
|
-
p_sha = sub.add_parser(
|
|
2502
|
-
"shadow-report",
|
|
2503
|
-
help="Read agents/runtime/council/shadow-log.jsonl and print the 7-day "
|
|
2504
|
-
"rolling disagreement rate + SLO status (step-9 P10).",
|
|
2505
|
-
)
|
|
2506
|
-
p_sha.add_argument("--log", default=None,
|
|
2507
|
-
help="Path to the shadow log (default: "
|
|
2508
|
-
"agents/runtime/council/shadow-log.jsonl).")
|
|
2509
|
-
p_sha.add_argument("--window-days", type=int, default=7,
|
|
2510
|
-
help="Rolling window in days (default: 7).")
|
|
2511
|
-
|
|
2512
|
-
return parser
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
def _add_prose_synthesis_arg(p: argparse.ArgumentParser) -> None:
|
|
2516
|
-
"""R4 Q4 escape hatch — toggle structured vs prose synthesis."""
|
|
2517
|
-
group = p.add_mutually_exclusive_group()
|
|
2518
|
-
group.add_argument("--prose-synthesis", dest="prose_synthesis",
|
|
2519
|
-
action="store_const", const=True, default=None,
|
|
2520
|
-
help="Force open-ended prose synthesis (bare slot) "
|
|
2521
|
-
"regardless of lens. R4 Q4 escape hatch.")
|
|
2522
|
-
group.add_argument("--no-prose-synthesis", dest="prose_synthesis",
|
|
2523
|
-
action="store_const", const=False,
|
|
2524
|
-
help="Force the structured default decision-lens "
|
|
2525
|
-
"template even on a creative lens "
|
|
2526
|
-
"(design / optimize). Symmetric escape hatch.")
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
def main(argv: list[str] | None = None) -> int:
|
|
2530
|
-
args = build_parser().parse_args(argv)
|
|
2531
|
-
try:
|
|
2532
|
-
if args.cmd == "estimate":
|
|
2533
|
-
return cmd_estimate(args)
|
|
2534
|
-
if args.cmd == "run":
|
|
2535
|
-
return cmd_run(args)
|
|
2536
|
-
if args.cmd == "debate":
|
|
2537
|
-
return cmd_debate(args)
|
|
2538
|
-
if args.cmd == "render":
|
|
2539
|
-
return cmd_render(args)
|
|
2540
|
-
if args.cmd == "replay":
|
|
2541
|
-
return cmd_replay(args)
|
|
2542
|
-
if args.cmd == "quota":
|
|
2543
|
-
return cmd_quota(args)
|
|
2544
|
-
if args.cmd == "shadow-report":
|
|
2545
|
-
return cmd_shadow_report(args)
|
|
2546
|
-
except CouncilDisabledError as exc:
|
|
2547
|
-
sys.stderr.write(f"❌ council:{args.cmd}: {exc}\n")
|
|
2548
|
-
return 2
|
|
2549
|
-
except (BundleTooLarge, InvalidModeError, FileNotFoundError,
|
|
2550
|
-
argparse.ArgumentTypeError) as exc:
|
|
2551
|
-
sys.stderr.write(f"❌ council:{args.cmd}: {exc}\n")
|
|
2552
|
-
return 2
|
|
2553
|
-
return 1
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
if __name__ == "__main__":
|
|
2557
|
-
raise SystemExit(main())
|