@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,1799 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Persistent chat-history log for crash recovery.
|
|
3
|
-
|
|
4
|
-
Maintains `agents/runtime/.agent-chat-history` — a JSONL file whose
|
|
5
|
-
first line is a header (schema version, started timestamp, cadence
|
|
6
|
-
frequency) and whose remaining lines are append-only entries (user
|
|
7
|
-
messages, phases, tool calls, questions, answers, decisions, commits).
|
|
8
|
-
|
|
9
|
-
Sessions are identified per-entry via the `s` field — a deterministic
|
|
10
|
-
16-char prefix derived from the platform's `session_id`. Multiple
|
|
11
|
-
sessions coexist in one file; each entry self-identifies. No ownership
|
|
12
|
-
layer, no sidecar, no auto-adopt — every hook invocation simply appends
|
|
13
|
-
with its own session tag.
|
|
14
|
-
|
|
15
|
-
File path defaults to `agents/runtime/.agent-chat-history` (relative to CWD) and
|
|
16
|
-
can be overridden via `$AGENT_CHAT_HISTORY_FILE` (used by tests).
|
|
17
|
-
|
|
18
|
-
Usage:
|
|
19
|
-
python3 scripts/chat_history.py init [--freq per_phase]
|
|
20
|
-
python3 scripts/chat_history.py append --type phase --json '{...}'
|
|
21
|
-
python3 scripts/chat_history.py status
|
|
22
|
-
python3 scripts/chat_history.py reset --entries-json '[...]' [--freq per_phase]
|
|
23
|
-
python3 scripts/chat_history.py prepend --entries-json '[...]'
|
|
24
|
-
python3 scripts/chat_history.py read [--last N | --all] [--session <id>]
|
|
25
|
-
python3 scripts/chat_history.py sessions [--limit N] [--json]
|
|
26
|
-
python3 scripts/chat_history.py prune-sessions [--max N] [--dry-run]
|
|
27
|
-
python3 scripts/chat_history.py clear
|
|
28
|
-
python3 scripts/chat_history.py rotate --max-kb 256 --mode rotate
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
from __future__ import annotations
|
|
32
|
-
|
|
33
|
-
import argparse
|
|
34
|
-
import datetime as dt
|
|
35
|
-
import hashlib
|
|
36
|
-
import json
|
|
37
|
-
import os
|
|
38
|
-
import re
|
|
39
|
-
import sys
|
|
40
|
-
import uuid
|
|
41
|
-
from collections import Counter, deque
|
|
42
|
-
from pathlib import Path
|
|
43
|
-
from typing import Any
|
|
44
|
-
|
|
45
|
-
DEFAULT_FILE = "agents/runtime/.agent-chat-history"
|
|
46
|
-
DEFAULT_SETTINGS_FILE = ".agent-settings.yml"
|
|
47
|
-
SCHEMA_VERSION = 4
|
|
48
|
-
DEFAULT_MAX_SESSIONS = 5
|
|
49
|
-
VALID_FREQS = {"per_turn", "per_phase", "per_tool"}
|
|
50
|
-
VALID_OVERFLOW = {"rotate", "condense"}
|
|
51
|
-
|
|
52
|
-
# Replay-mode signal — when set, every write to the on-disk transcript
|
|
53
|
-
# is a no-op. Honoured per `docs/contracts/hook-architecture-v1.md`
|
|
54
|
-
# § Replay mode so fixture dispatches never mutate real session state.
|
|
55
|
-
REPLAY_ENV_VAR = "AGENT_CONFIG_REPLAY"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def _is_replay_mode() -> bool:
|
|
59
|
-
return os.environ.get(REPLAY_ENV_VAR, "").strip() == "1"
|
|
60
|
-
_WS_RE = re.compile(r"\s+")
|
|
61
|
-
SESSION_ID_LEN = 16
|
|
62
|
-
SESSION_ID_UNKNOWN = "<unknown>"
|
|
63
|
-
SESSION_ID_LEGACY = "<legacy>"
|
|
64
|
-
# Sentinel for entries without an ``agent`` field — legacy rows or
|
|
65
|
-
# direct ``append`` calls that bypassed the platform-hook surface.
|
|
66
|
-
# Used by the ``agent`` filter on :func:`read_entries`, the AGENTS
|
|
67
|
-
# column in :func:`list_sessions`, and the ``agents`` aggregation in
|
|
68
|
-
# :func:`status` so cross-agent setups can spot unattributed traffic
|
|
69
|
-
# without a separate query.
|
|
70
|
-
AGENT_UNKNOWN = "<unknown>"
|
|
71
|
-
|
|
72
|
-
# Per-entry-type text-length caps. 0 = full text, no whitespace collapse,
|
|
73
|
-
# verbatim. N > 0 = collapse whitespace then slice to N chars and append a
|
|
74
|
-
# "… [+K chars]" suffix so the log self-reports truncation. Overridable via
|
|
75
|
-
# chat_history.text_limits.{user,agent,tool,phase} in .agent-settings.yml.
|
|
76
|
-
DEFAULT_TEXT_LIMITS = {"user": 0, "agent": 5000, "tool": 200, "phase": 200}
|
|
77
|
-
|
|
78
|
-
# Exit codes for the CLI. Distinct codes let shell callers branch on state.
|
|
79
|
-
EXIT_OK = 0
|
|
80
|
-
EXIT_BAD_ARGS = 2
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
def file_path() -> Path:
|
|
84
|
-
return Path(os.environ.get("AGENT_CHAT_HISTORY_FILE") or DEFAULT_FILE)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _now() -> str:
|
|
88
|
-
return dt.datetime.now(dt.timezone.utc).isoformat(timespec="seconds")
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def fingerprint(value: str) -> str:
|
|
92
|
-
"""SHA-256 of the normalized input (whitespace collapsed).
|
|
93
|
-
|
|
94
|
-
In v4 the input is the platform's ``session_id`` (or any stable
|
|
95
|
-
string). In v3 callers passed the first user message; the function
|
|
96
|
-
is signature-stable so v3 readers continue to work.
|
|
97
|
-
"""
|
|
98
|
-
normalized = _WS_RE.sub(" ", value or "").strip()
|
|
99
|
-
return hashlib.sha256(normalized.encode("utf-8")).hexdigest()
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def derive_session_tag(session_id: str) -> str:
|
|
103
|
-
"""Map a platform's ``session_id`` to the 16-char ``s`` body tag.
|
|
104
|
-
|
|
105
|
-
Deterministic — same input always yields the same tag, so stateless
|
|
106
|
-
hook invocations within one session converge on a single ``s``
|
|
107
|
-
without needing any cached state on disk.
|
|
108
|
-
"""
|
|
109
|
-
if not session_id:
|
|
110
|
-
return SESSION_ID_UNKNOWN
|
|
111
|
-
return fingerprint(session_id)[:SESSION_ID_LEN]
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
def _preview(msg: str, n: int = 80) -> str:
|
|
115
|
-
flat = _WS_RE.sub(" ", msg or "").strip()
|
|
116
|
-
return flat[:n]
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
def _extract_text(obj: dict[str, Any]) -> str:
|
|
120
|
-
"""Return the most-meaningful text payload of an entry, or empty.
|
|
121
|
-
|
|
122
|
-
Mirrors the fallback used by ``list_sessions`` for the ``preview``
|
|
123
|
-
field: top-level ``text`` first, then ``payload.text``.
|
|
124
|
-
"""
|
|
125
|
-
text = obj.get("text")
|
|
126
|
-
if not isinstance(text, str) or not text:
|
|
127
|
-
payload = obj.get("payload")
|
|
128
|
-
if isinstance(payload, dict):
|
|
129
|
-
text = payload.get("text")
|
|
130
|
-
return text if isinstance(text, str) else ""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def _summarize_session(head: list[dict[str, Any]],
|
|
134
|
-
tail: list[dict[str, Any]],
|
|
135
|
-
total: int,
|
|
136
|
-
n: int = 60) -> str:
|
|
137
|
-
"""Build a one-line summary from sampled head/tail entries.
|
|
138
|
-
|
|
139
|
-
Sample = head (≤5 oldest) + tail (≤5 newest), deduplicated by
|
|
140
|
-
object identity (overlap is possible when ``total`` ≤ 9). Format:
|
|
141
|
-
|
|
142
|
-
- both first and last user prose: ``"<first> → <last>"``
|
|
143
|
-
- one user prose only / both same: ``"<first>"``
|
|
144
|
-
- no user prose: ``"(<total> entries — no user
|
|
145
|
-
prompts; t-mix: …)"``
|
|
146
|
-
|
|
147
|
-
Each side capped at ``n`` chars via :func:`_preview`. Designed for
|
|
148
|
-
token-cheap session listings — caller never needs the full body.
|
|
149
|
-
"""
|
|
150
|
-
seen: set[int] = set()
|
|
151
|
-
sample: list[dict[str, Any]] = []
|
|
152
|
-
for e in list(head) + list(tail):
|
|
153
|
-
oid = id(e)
|
|
154
|
-
if oid in seen:
|
|
155
|
-
continue
|
|
156
|
-
seen.add(oid)
|
|
157
|
-
sample.append(e)
|
|
158
|
-
|
|
159
|
-
user_texts = [
|
|
160
|
-
_extract_text(e)
|
|
161
|
-
for e in sample
|
|
162
|
-
if e.get("t") == "user" and _extract_text(e)
|
|
163
|
-
]
|
|
164
|
-
if user_texts:
|
|
165
|
-
first = _preview(user_texts[0], n)
|
|
166
|
-
if len(user_texts) > 1 and user_texts[-1] != user_texts[0]:
|
|
167
|
-
last = _preview(user_texts[-1], n)
|
|
168
|
-
return f"{first} → {last}"
|
|
169
|
-
return first
|
|
170
|
-
|
|
171
|
-
kinds = Counter(e.get("t", "?") for e in sample)
|
|
172
|
-
mix = " ".join(f"{k}×{v}" for k, v in kinds.most_common())
|
|
173
|
-
return f"({total} entries — no user prompts; t-mix: {mix})"
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def _session_tag_enabled() -> bool:
|
|
177
|
-
"""True iff `append()` should auto-fill the `s` field when missing.
|
|
178
|
-
|
|
179
|
-
Default is on (v3+ contract). Kill-switch via
|
|
180
|
-
`AGENT_CHAT_HISTORY_SESSION_TAG=false` reverts to v2 entry shape
|
|
181
|
-
so a bad rollout can be reverted without code change.
|
|
182
|
-
"""
|
|
183
|
-
return os.environ.get(
|
|
184
|
-
"AGENT_CHAT_HISTORY_SESSION_TAG", "true"
|
|
185
|
-
).strip().lower() != "false"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def _last_body_session_id(path: Path | None = None) -> str:
|
|
189
|
-
"""Return the ``s`` of the most recent body entry, or ``<unknown>``.
|
|
190
|
-
|
|
191
|
-
Used as a fallback ``s`` for CLI-driven appends that have no
|
|
192
|
-
platform session context. Reads the file tail-first to keep the
|
|
193
|
-
cost constant on large logs.
|
|
194
|
-
"""
|
|
195
|
-
p = path or file_path()
|
|
196
|
-
if not p.is_file() or p.stat().st_size == 0:
|
|
197
|
-
return SESSION_ID_UNKNOWN
|
|
198
|
-
try:
|
|
199
|
-
with p.open(encoding="utf-8") as fh:
|
|
200
|
-
lines = fh.readlines()
|
|
201
|
-
except OSError:
|
|
202
|
-
return SESSION_ID_UNKNOWN
|
|
203
|
-
for line in reversed(lines):
|
|
204
|
-
line = line.strip()
|
|
205
|
-
if not line:
|
|
206
|
-
continue
|
|
207
|
-
try:
|
|
208
|
-
obj = json.loads(line)
|
|
209
|
-
except json.JSONDecodeError:
|
|
210
|
-
continue
|
|
211
|
-
if not isinstance(obj, dict) or obj.get("t") == "header":
|
|
212
|
-
continue
|
|
213
|
-
sid = obj.get("s")
|
|
214
|
-
if isinstance(sid, str) and sid:
|
|
215
|
-
return sid
|
|
216
|
-
return SESSION_ID_UNKNOWN
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def read_header(path: Path | None = None) -> dict[str, Any] | None:
|
|
220
|
-
"""Read the header.
|
|
221
|
-
|
|
222
|
-
Forward-compatible: v3 headers (`fp`, `preview`, `former_fps`,
|
|
223
|
-
`session`) parse fine; their legacy fields are returned verbatim
|
|
224
|
-
so older readers keep working. The next write (init/reset)
|
|
225
|
-
rewrites the file with a clean v4 header.
|
|
226
|
-
"""
|
|
227
|
-
p = path or file_path()
|
|
228
|
-
if not p.is_file() or p.stat().st_size == 0:
|
|
229
|
-
return None
|
|
230
|
-
try:
|
|
231
|
-
with p.open(encoding="utf-8") as fh:
|
|
232
|
-
first = fh.readline().strip()
|
|
233
|
-
if not first:
|
|
234
|
-
return None
|
|
235
|
-
obj = json.loads(first)
|
|
236
|
-
if not (isinstance(obj, dict) and obj.get("t") == "header"):
|
|
237
|
-
return None
|
|
238
|
-
return obj
|
|
239
|
-
except (json.JSONDecodeError, OSError):
|
|
240
|
-
return None
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def _build_header(freq: str) -> dict[str, Any]:
|
|
244
|
-
return {
|
|
245
|
-
"t": "header",
|
|
246
|
-
"v": SCHEMA_VERSION,
|
|
247
|
-
"started": _now(),
|
|
248
|
-
"freq": freq,
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
def init(freq: str = "per_phase", *,
|
|
253
|
-
path: Path | None = None) -> dict[str, Any]:
|
|
254
|
-
"""Overwrite the file with a fresh v4 header."""
|
|
255
|
-
if freq not in VALID_FREQS:
|
|
256
|
-
raise ValueError(f"freq must be one of {sorted(VALID_FREQS)}")
|
|
257
|
-
p = path or file_path()
|
|
258
|
-
header = _build_header(freq)
|
|
259
|
-
if _is_replay_mode():
|
|
260
|
-
return header
|
|
261
|
-
p.parent.mkdir(parents=True, exist_ok=True)
|
|
262
|
-
with p.open("w", encoding="utf-8") as fh:
|
|
263
|
-
fh.write(json.dumps(header, ensure_ascii=False) + "\n")
|
|
264
|
-
return header
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def migrate_header(path: Path | None = None, *,
|
|
268
|
-
freq: str | None = None) -> dict[str, Any] | None:
|
|
269
|
-
"""Rewrite a stale header in-place, preserving body and ``started``.
|
|
270
|
-
|
|
271
|
-
Returns the new header on migration, ``None`` when the file is
|
|
272
|
-
missing/empty/unreadable or the header is already at
|
|
273
|
-
:data:`SCHEMA_VERSION`. v3 headers carry parseable ``v``/``freq``/
|
|
274
|
-
``started`` fields that are forward-compatible (see
|
|
275
|
-
:func:`read_header`); this helper is the only writer that flips
|
|
276
|
-
``v`` without destroying the body. Atomic — the body never
|
|
277
|
-
diverges from the header version mid-write.
|
|
278
|
-
"""
|
|
279
|
-
p = path or file_path()
|
|
280
|
-
existing = read_header(p)
|
|
281
|
-
if existing is None:
|
|
282
|
-
return None
|
|
283
|
-
try:
|
|
284
|
-
current_v = int(existing.get("v", 0))
|
|
285
|
-
except (TypeError, ValueError):
|
|
286
|
-
current_v = 0
|
|
287
|
-
if current_v >= SCHEMA_VERSION:
|
|
288
|
-
return None
|
|
289
|
-
chosen_freq = freq or existing.get("freq") or "per_phase"
|
|
290
|
-
if chosen_freq not in VALID_FREQS:
|
|
291
|
-
chosen_freq = "per_phase"
|
|
292
|
-
new_header = _build_header(chosen_freq)
|
|
293
|
-
# Preserve the original session start so chronology survives.
|
|
294
|
-
if isinstance(existing.get("started"), str):
|
|
295
|
-
new_header["started"] = existing["started"]
|
|
296
|
-
raw = p.read_text(encoding="utf-8")
|
|
297
|
-
# splitlines() drops the trailing newline; rebuild it on write so
|
|
298
|
-
# downstream readers (which expect newline-delimited JSONL) stay
|
|
299
|
-
# happy. Empty body → just the header line + newline.
|
|
300
|
-
lines = raw.splitlines()
|
|
301
|
-
if not lines:
|
|
302
|
-
return None
|
|
303
|
-
lines[0] = json.dumps(new_header, ensure_ascii=False)
|
|
304
|
-
_atomic_write_text(p, "\n".join(lines) + "\n")
|
|
305
|
-
return new_header
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
def append(entry: dict[str, Any], *, path: Path | None = None,
|
|
309
|
-
session: str | None = None) -> None:
|
|
310
|
-
"""Append one entry. Entry must be a dict; `ts` is auto-filled.
|
|
311
|
-
|
|
312
|
-
Schema v4 stamps every body entry with `s` (16-char session tag).
|
|
313
|
-
Resolution order: caller-supplied `session=` wins; pre-filled
|
|
314
|
-
`entry['s']` is preserved; otherwise the most recent body entry's
|
|
315
|
-
`s` is reused (CLI fallback). Kill-switch
|
|
316
|
-
`AGENT_CHAT_HISTORY_SESSION_TAG=false` skips auto-fill for
|
|
317
|
-
downgrade-friendly rollouts.
|
|
318
|
-
|
|
319
|
-
No ownership validation: each entry self-identifies via `s`, so
|
|
320
|
-
multiple sessions coexist in one file without conflict.
|
|
321
|
-
"""
|
|
322
|
-
if not isinstance(entry, dict) or not entry.get("t"):
|
|
323
|
-
raise ValueError("entry must be a dict with non-empty 't' key")
|
|
324
|
-
if entry["t"] == "header":
|
|
325
|
-
raise ValueError("use init() to write the header, not append()")
|
|
326
|
-
p = path or file_path()
|
|
327
|
-
entry.setdefault("ts", _now())
|
|
328
|
-
if session is not None:
|
|
329
|
-
entry["s"] = session
|
|
330
|
-
elif "s" not in entry and _session_tag_enabled():
|
|
331
|
-
entry["s"] = _last_body_session_id(p)
|
|
332
|
-
if _is_replay_mode():
|
|
333
|
-
return
|
|
334
|
-
with p.open("a", encoding="utf-8") as fh:
|
|
335
|
-
fh.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
def _atomic_write_text(p: Path, text: str) -> None:
|
|
339
|
-
"""Write ``text`` to ``p`` atomically with a per-call unique tmp path.
|
|
340
|
-
|
|
341
|
-
Multiple processes writing to the same target use disjoint tmp paths
|
|
342
|
-
(PID + uuid), so concurrent writes no longer collide on a shared
|
|
343
|
-
``.tmp`` file. The final ``replace`` is atomic on POSIX.
|
|
344
|
-
|
|
345
|
-
Under `AGENT_CONFIG_REPLAY=1` the call is a no-op.
|
|
346
|
-
"""
|
|
347
|
-
if _is_replay_mode():
|
|
348
|
-
return
|
|
349
|
-
tmp = p.with_suffix(
|
|
350
|
-
f"{p.suffix}.{os.getpid()}.{uuid.uuid4().hex[:8]}.tmp",
|
|
351
|
-
)
|
|
352
|
-
try:
|
|
353
|
-
tmp.write_text(text, encoding="utf-8")
|
|
354
|
-
tmp.replace(p)
|
|
355
|
-
except Exception:
|
|
356
|
-
try:
|
|
357
|
-
tmp.unlink()
|
|
358
|
-
except OSError:
|
|
359
|
-
pass
|
|
360
|
-
raise
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
def _normalize_entries(entries: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
364
|
-
"""Validate + fill `ts` on each entry. Reject headers and empty `t`."""
|
|
365
|
-
out: list[dict[str, Any]] = []
|
|
366
|
-
for raw in entries or []:
|
|
367
|
-
if not isinstance(raw, dict) or not raw.get("t"):
|
|
368
|
-
raise ValueError("each entry must be a dict with non-empty 't' key")
|
|
369
|
-
if raw["t"] == "header":
|
|
370
|
-
raise ValueError("entries must not contain headers")
|
|
371
|
-
e = dict(raw)
|
|
372
|
-
e.setdefault("ts", _now())
|
|
373
|
-
out.append(e)
|
|
374
|
-
return out
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
def reset_with_entries(entries: list[dict[str, Any]],
|
|
378
|
-
freq: str = "per_phase", *,
|
|
379
|
-
path: Path | None = None) -> dict[str, Any]:
|
|
380
|
-
"""Discard current file contents and rewrite with a fresh header + entries.
|
|
381
|
-
|
|
382
|
-
Used for the 'Replace' flow: the in-memory history supersedes
|
|
383
|
-
whatever is on disk. v4 carries no per-session header state, so
|
|
384
|
-
the rewrite is a clean slate; pre-existing entries' ``s`` tags
|
|
385
|
-
survive only if the caller passes them through ``entries``.
|
|
386
|
-
"""
|
|
387
|
-
if freq not in VALID_FREQS:
|
|
388
|
-
raise ValueError(f"freq must be one of {sorted(VALID_FREQS)}")
|
|
389
|
-
p = path or file_path()
|
|
390
|
-
header = _build_header(freq)
|
|
391
|
-
body = _normalize_entries(entries)
|
|
392
|
-
p.parent.mkdir(parents=True, exist_ok=True)
|
|
393
|
-
lines = [json.dumps(header, ensure_ascii=False)]
|
|
394
|
-
lines += [json.dumps(e, ensure_ascii=False) for e in body]
|
|
395
|
-
_atomic_write_text(p, "\n".join(lines) + "\n")
|
|
396
|
-
return header
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
def prepend_entries(entries: list[dict[str, Any]], *,
|
|
400
|
-
path: Path | None = None) -> int:
|
|
401
|
-
"""Insert entries right after the header, before existing body entries.
|
|
402
|
-
|
|
403
|
-
Used for the 'Merge' flow: the in-memory history (older) is placed
|
|
404
|
-
before the file's existing body (newer from the adopting session).
|
|
405
|
-
Returns the number of entries prepended. Header untouched.
|
|
406
|
-
"""
|
|
407
|
-
p = path or file_path()
|
|
408
|
-
if not p.is_file():
|
|
409
|
-
raise FileNotFoundError(f"no file at {p}")
|
|
410
|
-
with p.open(encoding="utf-8") as fh:
|
|
411
|
-
existing = fh.readlines()
|
|
412
|
-
if not existing:
|
|
413
|
-
raise ValueError(f"empty file at {p}")
|
|
414
|
-
header_line = existing[0]
|
|
415
|
-
body = existing[1:]
|
|
416
|
-
new_lines = [json.dumps(e, ensure_ascii=False) + "\n"
|
|
417
|
-
for e in _normalize_entries(entries)]
|
|
418
|
-
_atomic_write_text(
|
|
419
|
-
p, header_line + "".join(new_lines) + "".join(body),
|
|
420
|
-
)
|
|
421
|
-
return len(new_lines)
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
def clear(*, path: Path | None = None) -> None:
|
|
425
|
-
if _is_replay_mode():
|
|
426
|
-
return
|
|
427
|
-
p = path or file_path()
|
|
428
|
-
if p.exists():
|
|
429
|
-
p.unlink()
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
def read_entries(last: int | None = None, *,
|
|
433
|
-
path: Path | None = None,
|
|
434
|
-
session: str | None = None,
|
|
435
|
-
agent: str | None = None) -> list[dict[str, Any]]:
|
|
436
|
-
"""Return entries (excluding the header) as a list of dicts.
|
|
437
|
-
|
|
438
|
-
`last=None` returns all entries; `last=N` returns the trailing N.
|
|
439
|
-
`session=None` keeps legacy "return everything" behaviour; an explicit
|
|
440
|
-
string filters by exact match on each entry's `s` field. The `last`
|
|
441
|
-
slice is applied **after** the session/agent filters so callers
|
|
442
|
-
always get the trailing N within the selected scope.
|
|
443
|
-
|
|
444
|
-
`agent=None` returns entries from every agent. An explicit string
|
|
445
|
-
matches the body row's ``agent`` field; the sentinel ``<unknown>``
|
|
446
|
-
matches entries without an ``agent`` field (legacy or
|
|
447
|
-
unattributed). Filtering is exact-match — no glob, no regex.
|
|
448
|
-
|
|
449
|
-
Malformed lines are skipped silently.
|
|
450
|
-
"""
|
|
451
|
-
p = path or file_path()
|
|
452
|
-
if not p.is_file():
|
|
453
|
-
return []
|
|
454
|
-
entries: list[dict[str, Any]] = []
|
|
455
|
-
with p.open(encoding="utf-8") as fh:
|
|
456
|
-
for i, line in enumerate(fh):
|
|
457
|
-
line = line.strip()
|
|
458
|
-
if not line:
|
|
459
|
-
continue
|
|
460
|
-
try:
|
|
461
|
-
obj = json.loads(line)
|
|
462
|
-
except json.JSONDecodeError:
|
|
463
|
-
continue
|
|
464
|
-
if i == 0 and isinstance(obj, dict) and obj.get("t") == "header":
|
|
465
|
-
continue
|
|
466
|
-
if isinstance(obj, dict):
|
|
467
|
-
entries.append(obj)
|
|
468
|
-
if session is not None:
|
|
469
|
-
entries = [e for e in entries if e.get("s") == session]
|
|
470
|
-
if agent is not None:
|
|
471
|
-
if agent == AGENT_UNKNOWN:
|
|
472
|
-
entries = [e for e in entries if not e.get("agent")]
|
|
473
|
-
else:
|
|
474
|
-
entries = [e for e in entries if e.get("agent") == agent]
|
|
475
|
-
if last is not None and last >= 0:
|
|
476
|
-
entries = entries[-last:]
|
|
477
|
-
return entries
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
def read_entries_for_current(path: Path | None = None,
|
|
481
|
-
last: int | None = None) -> list[dict[str, Any]]:
|
|
482
|
-
"""Return entries scoped to the most recent session in the file.
|
|
483
|
-
|
|
484
|
-
The "current" session in v4 is the ``s`` of the most recent body
|
|
485
|
-
entry; entries with that ``s`` are returned. Kill-switch
|
|
486
|
-
``AGENT_CHAT_HISTORY_SESSION_FILTER=false`` short-circuits to
|
|
487
|
-
``read_entries(session=None)`` for the v2 "return everything"
|
|
488
|
-
behaviour.
|
|
489
|
-
"""
|
|
490
|
-
p = path or file_path()
|
|
491
|
-
kill = os.environ.get(
|
|
492
|
-
"AGENT_CHAT_HISTORY_SESSION_FILTER", "true",
|
|
493
|
-
).strip().lower()
|
|
494
|
-
if kill == "false":
|
|
495
|
-
return read_entries(last=last, path=p, session=None)
|
|
496
|
-
return read_entries(last=last, path=p, session=_last_body_session_id(p))
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
def list_sessions(path: Path | None = None,
|
|
500
|
-
*, summary: bool = False) -> list[dict[str, Any]]:
|
|
501
|
-
"""Return one bucket per distinct session id observed in the body.
|
|
502
|
-
|
|
503
|
-
Each bucket carries ``id``, ``count``, ``first_ts``, ``last_ts``,
|
|
504
|
-
``preview``. Preview = the first ``t == "user"`` entry's ``text``
|
|
505
|
-
in the session, truncated to 80 chars; falls back to the first
|
|
506
|
-
entry of any type when no user-typed entry exists.
|
|
507
|
-
|
|
508
|
-
When ``summary=True``, each bucket also carries a ``summary`` field
|
|
509
|
-
built from at most 10 sampled entries per session (5 oldest + 5
|
|
510
|
-
newest, deduplicated). Designed for token-cheap listings: callers
|
|
511
|
-
can render ``summary`` instead of pulling all entries via
|
|
512
|
-
:func:`read`. See :func:`_summarize_session` for the format.
|
|
513
|
-
|
|
514
|
-
v4 has no per-session header state, so buckets are derived from
|
|
515
|
-
body ``s`` values only. ``<legacy>`` and ``<unknown>`` appear as
|
|
516
|
-
their own buckets when present in the body. Order is by
|
|
517
|
-
``last_ts`` descending.
|
|
518
|
-
"""
|
|
519
|
-
p = path or file_path()
|
|
520
|
-
buckets: dict[str, dict[str, Any]] = {}
|
|
521
|
-
|
|
522
|
-
def _bucket(sid: str) -> dict[str, Any]:
|
|
523
|
-
b = buckets.get(sid)
|
|
524
|
-
if b is None:
|
|
525
|
-
b = {"id": sid, "count": 0, "first_ts": None,
|
|
526
|
-
"last_ts": None, "preview": "", "agents": []}
|
|
527
|
-
if summary:
|
|
528
|
-
b["_head"] = []
|
|
529
|
-
b["_tail"] = deque(maxlen=5)
|
|
530
|
-
buckets[sid] = b
|
|
531
|
-
return b
|
|
532
|
-
|
|
533
|
-
if p.is_file():
|
|
534
|
-
with p.open(encoding="utf-8") as fh:
|
|
535
|
-
for i, line in enumerate(fh):
|
|
536
|
-
line = line.strip()
|
|
537
|
-
if not line:
|
|
538
|
-
continue
|
|
539
|
-
try:
|
|
540
|
-
obj = json.loads(line)
|
|
541
|
-
except json.JSONDecodeError:
|
|
542
|
-
continue
|
|
543
|
-
if not isinstance(obj, dict):
|
|
544
|
-
continue
|
|
545
|
-
if i == 0 and obj.get("t") == "header":
|
|
546
|
-
continue
|
|
547
|
-
sid = obj.get("s")
|
|
548
|
-
if not isinstance(sid, str) or not sid:
|
|
549
|
-
sid = SESSION_ID_LEGACY
|
|
550
|
-
b = _bucket(sid)
|
|
551
|
-
b["count"] += 1
|
|
552
|
-
agent = obj.get("agent") if isinstance(obj.get("agent"), str) else None
|
|
553
|
-
tag = agent if agent else AGENT_UNKNOWN
|
|
554
|
-
if tag not in b["agents"]:
|
|
555
|
-
b["agents"].append(tag)
|
|
556
|
-
ts = obj.get("ts")
|
|
557
|
-
if isinstance(ts, str) and ts:
|
|
558
|
-
if b["first_ts"] is None or ts < b["first_ts"]:
|
|
559
|
-
b["first_ts"] = ts
|
|
560
|
-
if b["last_ts"] is None or ts > b["last_ts"]:
|
|
561
|
-
b["last_ts"] = ts
|
|
562
|
-
if summary:
|
|
563
|
-
if len(b["_head"]) < 5:
|
|
564
|
-
b["_head"].append(obj)
|
|
565
|
-
b["_tail"].append(obj)
|
|
566
|
-
if not b["preview"] or b.get("_preview_from") != "user":
|
|
567
|
-
if obj.get("t") == "user":
|
|
568
|
-
text = obj.get("text") or obj.get("payload", {}).get("text", "")
|
|
569
|
-
if isinstance(text, str) and text:
|
|
570
|
-
b["preview"] = _preview(text)
|
|
571
|
-
b["_preview_from"] = "user"
|
|
572
|
-
elif not b["preview"]:
|
|
573
|
-
text = obj.get("text") or ""
|
|
574
|
-
if isinstance(text, str) and text:
|
|
575
|
-
b["preview"] = _preview(text)
|
|
576
|
-
b["_preview_from"] = "any"
|
|
577
|
-
|
|
578
|
-
out: list[dict[str, Any]] = []
|
|
579
|
-
for b in buckets.values():
|
|
580
|
-
b.pop("_preview_from", None)
|
|
581
|
-
b["agents"] = sorted(b["agents"])
|
|
582
|
-
if summary:
|
|
583
|
-
head = b.pop("_head", [])
|
|
584
|
-
tail = list(b.pop("_tail", ()))
|
|
585
|
-
b["summary"] = _summarize_session(head, tail, b["count"])
|
|
586
|
-
out.append(b)
|
|
587
|
-
out.sort(key=lambda x: x["last_ts"] or "", reverse=True)
|
|
588
|
-
return out
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
def status(*, path: Path | None = None) -> dict[str, Any]:
|
|
592
|
-
p = path or file_path()
|
|
593
|
-
if not p.is_file():
|
|
594
|
-
return {"exists": False, "path": str(p)}
|
|
595
|
-
header = read_header(p)
|
|
596
|
-
entry_count = 0
|
|
597
|
-
per_agent: dict[str, int] = {}
|
|
598
|
-
with p.open(encoding="utf-8") as fh:
|
|
599
|
-
for i, line in enumerate(fh):
|
|
600
|
-
line = line.strip()
|
|
601
|
-
if not line:
|
|
602
|
-
continue
|
|
603
|
-
try:
|
|
604
|
-
obj = json.loads(line)
|
|
605
|
-
except json.JSONDecodeError:
|
|
606
|
-
continue
|
|
607
|
-
if not isinstance(obj, dict):
|
|
608
|
-
continue
|
|
609
|
-
if i == 0 and obj.get("t") == "header":
|
|
610
|
-
continue
|
|
611
|
-
entry_count += 1
|
|
612
|
-
agent = obj.get("agent") if isinstance(obj.get("agent"), str) else None
|
|
613
|
-
tag = agent if agent else AGENT_UNKNOWN
|
|
614
|
-
per_agent[tag] = per_agent.get(tag, 0) + 1
|
|
615
|
-
size = p.stat().st_size
|
|
616
|
-
agents = {
|
|
617
|
-
"total": len(per_agent),
|
|
618
|
-
"per_agent": dict(sorted(per_agent.items())),
|
|
619
|
-
}
|
|
620
|
-
return {
|
|
621
|
-
"exists": True,
|
|
622
|
-
"path": str(p),
|
|
623
|
-
"size_bytes": size,
|
|
624
|
-
"size_kb": round(size / 1024, 1),
|
|
625
|
-
"entries": entry_count,
|
|
626
|
-
"header": header,
|
|
627
|
-
"agents": agents,
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
def _load_chat_history_section(settings_path: Path) -> dict | None:
|
|
632
|
-
"""Return the ``chat_history`` mapping from .agent-settings.yml or None.
|
|
633
|
-
|
|
634
|
-
Centralized loader (road-to-portable-dev-preferences P3): tolerance
|
|
635
|
-
contract handles missing file / malformed YAML / no PyYAML uniformly.
|
|
636
|
-
No ``chat_history.*`` keys are whitelisted, so user-global cannot
|
|
637
|
-
leak into this section — the project file remains authoritative.
|
|
638
|
-
"""
|
|
639
|
-
try:
|
|
640
|
-
from scripts._lib.agent_settings import load_agent_settings
|
|
641
|
-
except ImportError: # pragma: no cover — script-style invocation
|
|
642
|
-
import sys as _sys
|
|
643
|
-
from pathlib import Path as _Path
|
|
644
|
-
_sys.path.insert(0, str(_Path(__file__).resolve().parent))
|
|
645
|
-
from _lib.agent_settings import load_agent_settings # type: ignore[import-not-found]
|
|
646
|
-
|
|
647
|
-
data = load_agent_settings(project_path=settings_path)
|
|
648
|
-
section = data.get("chat_history")
|
|
649
|
-
return section if isinstance(section, dict) else None
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
def _read_chat_history_enabled(settings_path: Path) -> bool:
|
|
653
|
-
"""Read chat_history.enabled from .agent-settings.yml.
|
|
654
|
-
|
|
655
|
-
Returns False when the file is missing, malformed, lacks the
|
|
656
|
-
`chat_history` section, or sets enabled to false. Default-deny so
|
|
657
|
-
`turn-check` is safe to run from projects that have not opted in.
|
|
658
|
-
"""
|
|
659
|
-
section = _load_chat_history_section(settings_path)
|
|
660
|
-
if section is None:
|
|
661
|
-
return False
|
|
662
|
-
return bool(section.get("enabled", False))
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
# Hook events that the platform-hook wrapper accepts. Mapped to entry
|
|
666
|
-
# types in HOOK_EVENT_ENTRY_TYPE; cadence filtering in
|
|
667
|
-
# CADENCE_EVENTS decides whether the event actually lands in the log
|
|
668
|
-
# given chat_history.frequency.
|
|
669
|
-
VALID_HOOK_EVENTS = (
|
|
670
|
-
"session_start", "session_end", "user_prompt", "agent_response",
|
|
671
|
-
"tool_use", "phase", "stop",
|
|
672
|
-
)
|
|
673
|
-
HOOK_EVENT_ENTRY_TYPE = {
|
|
674
|
-
"user_prompt": "user",
|
|
675
|
-
"agent_response": "agent",
|
|
676
|
-
"tool_use": "tool",
|
|
677
|
-
"phase": "phase",
|
|
678
|
-
"stop": "agent",
|
|
679
|
-
"session_end": "phase",
|
|
680
|
-
}
|
|
681
|
-
# Which events actually trigger an append for each frequency. session_*
|
|
682
|
-
# events are control plane (sidecar / init), not log entries, so they
|
|
683
|
-
# are absent from these sets.
|
|
684
|
-
CADENCE_EVENTS = {
|
|
685
|
-
"per_turn": frozenset({"stop", "agent_response", "user_prompt"}),
|
|
686
|
-
"per_phase": frozenset({"phase", "stop", "user_prompt"}),
|
|
687
|
-
"per_tool": frozenset({"tool_use"}),
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
# Per-platform mapping from the platform's native hook event name to our
|
|
691
|
-
# internal VALID_HOOK_EVENTS. Used by hook_dispatch() to translate
|
|
692
|
-
# stdin JSON payloads coming from Claude Code, Augment Code, Cursor,
|
|
693
|
-
# Cline, Windsurf, and Gemini CLI into a unified entry-point. Sourced
|
|
694
|
-
# from agents/settings/contexts/chat-history-platform-hooks.md.
|
|
695
|
-
PLATFORM_EVENT_MAP: dict[str, dict[str, str]] = {
|
|
696
|
-
"claude": {
|
|
697
|
-
"SessionStart": "session_start",
|
|
698
|
-
"UserPromptSubmit": "user_prompt",
|
|
699
|
-
"PostToolUse": "tool_use",
|
|
700
|
-
"Stop": "stop",
|
|
701
|
-
"SessionEnd": "session_end",
|
|
702
|
-
"PreCompact": "phase",
|
|
703
|
-
},
|
|
704
|
-
# Cowork is the Claude desktop app's local-agent-mode runtime —
|
|
705
|
-
# built on top of the Claude Code CLI, so it speaks the same hook
|
|
706
|
-
# vocabulary (PascalCase, identical event payload shape including
|
|
707
|
-
# `transcript_path` for Stop). Listed as a separate platform so the
|
|
708
|
-
# `agent` field on body entries can distinguish Cowork sessions
|
|
709
|
-
# from plain Claude Code CLI / IDE sessions when both run against
|
|
710
|
-
# the same project.
|
|
711
|
-
#
|
|
712
|
-
# Upstream caveat: anthropics/claude-code#40495 reports that
|
|
713
|
-
# Cowork sessions silently ignore all three Claude Code settings
|
|
714
|
-
# sources (user, project, env), and #27398 reports plugin-scope
|
|
715
|
-
# `hooks/hooks.json` is excluded because Cowork spawns the CLI
|
|
716
|
-
# with `--setting-sources user`. Until those are resolved, the
|
|
717
|
-
# mapping below is dispatcher-ready but the lifecycle events do
|
|
718
|
-
# not actually fire from Cowork. See
|
|
719
|
-
# `agents/settings/contexts/chat-history-platform-hooks.md` § Cowork.
|
|
720
|
-
"cowork": {
|
|
721
|
-
"SessionStart": "session_start",
|
|
722
|
-
"UserPromptSubmit": "user_prompt",
|
|
723
|
-
"PostToolUse": "tool_use",
|
|
724
|
-
"Stop": "stop",
|
|
725
|
-
"SessionEnd": "session_end",
|
|
726
|
-
"PreCompact": "phase",
|
|
727
|
-
},
|
|
728
|
-
"augment": {
|
|
729
|
-
"SessionStart": "session_start",
|
|
730
|
-
"Stop": "stop",
|
|
731
|
-
"PostToolUse": "tool_use",
|
|
732
|
-
"SessionEnd": "session_end",
|
|
733
|
-
},
|
|
734
|
-
"cursor": {
|
|
735
|
-
"sessionStart": "session_start",
|
|
736
|
-
"sessionEnd": "session_end",
|
|
737
|
-
"afterAgentResponse": "agent_response",
|
|
738
|
-
"stop": "stop",
|
|
739
|
-
"postToolUse": "tool_use",
|
|
740
|
-
"beforeSubmitPrompt": "user_prompt",
|
|
741
|
-
},
|
|
742
|
-
"cline": {
|
|
743
|
-
"TaskStart": "session_start",
|
|
744
|
-
"TaskComplete": "session_end",
|
|
745
|
-
"UserPromptSubmit": "user_prompt",
|
|
746
|
-
"PostToolUse": "tool_use",
|
|
747
|
-
},
|
|
748
|
-
"windsurf": {
|
|
749
|
-
"pre_user_prompt": "user_prompt",
|
|
750
|
-
"post_cascade_response": "agent_response",
|
|
751
|
-
"post_cascade_response_with_transcript": "agent_response",
|
|
752
|
-
"post_setup_worktree": "phase",
|
|
753
|
-
},
|
|
754
|
-
"gemini": {
|
|
755
|
-
"SessionStart": "session_start",
|
|
756
|
-
"AfterAgent": "agent_response",
|
|
757
|
-
"AfterTool": "tool_use",
|
|
758
|
-
"SessionEnd": "session_end",
|
|
759
|
-
},
|
|
760
|
-
# Generic / pass-through — the caller already speaks our internal
|
|
761
|
-
# event vocabulary. Useful for shell snippets that want to invoke
|
|
762
|
-
# the dispatcher with a known event regardless of platform.
|
|
763
|
-
"generic": {ev: ev for ev in VALID_HOOK_EVENTS},
|
|
764
|
-
}
|
|
765
|
-
VALID_PLATFORMS = tuple(PLATFORM_EVENT_MAP.keys())
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
def _read_chat_history_frequency(settings_path: Path) -> str:
|
|
769
|
-
"""Read chat_history.frequency from .agent-settings.yml. Default per_phase."""
|
|
770
|
-
section = _load_chat_history_section(settings_path)
|
|
771
|
-
if section is None:
|
|
772
|
-
return "per_phase"
|
|
773
|
-
val = str(section.get("frequency", "per_phase")).lower()
|
|
774
|
-
return val if val in VALID_FREQS else "per_phase"
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
def _read_chat_history_max_sessions(settings_path: Path) -> int:
|
|
778
|
-
"""Read chat_history.max_sessions from .agent-settings.yml.
|
|
779
|
-
|
|
780
|
-
Default ``DEFAULT_MAX_SESSIONS`` (5). Values < 1 are clamped to 1.
|
|
781
|
-
Used by ``prune_sessions`` to decide how many distinct ``s`` tags
|
|
782
|
-
survive in the body.
|
|
783
|
-
"""
|
|
784
|
-
section = _load_chat_history_section(settings_path)
|
|
785
|
-
if section is None:
|
|
786
|
-
return DEFAULT_MAX_SESSIONS
|
|
787
|
-
try:
|
|
788
|
-
n = int(section.get("max_sessions", DEFAULT_MAX_SESSIONS))
|
|
789
|
-
except (TypeError, ValueError):
|
|
790
|
-
return DEFAULT_MAX_SESSIONS
|
|
791
|
-
return max(1, n)
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
def _read_text_limits(settings_path: Path) -> dict[str, int]:
|
|
795
|
-
"""Read chat_history.text_limits from .agent-settings.yml.
|
|
796
|
-
|
|
797
|
-
Returns a dict keyed by entry type (``user``, ``agent``, ``tool``,
|
|
798
|
-
``phase``) with int caps. Missing keys fall back to
|
|
799
|
-
``DEFAULT_TEXT_LIMITS``. ``0`` means "no slice, full text". Negative
|
|
800
|
-
values are clamped to 0. Non-int values are silently dropped.
|
|
801
|
-
"""
|
|
802
|
-
out = dict(DEFAULT_TEXT_LIMITS)
|
|
803
|
-
section = _load_chat_history_section(settings_path)
|
|
804
|
-
if section is None:
|
|
805
|
-
return out
|
|
806
|
-
overrides = section.get("text_limits")
|
|
807
|
-
if not isinstance(overrides, dict):
|
|
808
|
-
return out
|
|
809
|
-
for kind, val in overrides.items():
|
|
810
|
-
if not isinstance(kind, str):
|
|
811
|
-
continue
|
|
812
|
-
try:
|
|
813
|
-
n = int(val)
|
|
814
|
-
except (TypeError, ValueError):
|
|
815
|
-
continue
|
|
816
|
-
out[kind] = max(0, n)
|
|
817
|
-
return out
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
def _apply_text_limit(text: str, kind: str,
|
|
821
|
-
limits: dict[str, int]) -> str:
|
|
822
|
-
"""Slice ``text`` to the configured cap for ``kind``.
|
|
823
|
-
|
|
824
|
-
``limits[kind] == 0`` returns the text verbatim (whitespace
|
|
825
|
-
preserved). ``> 0`` collapses whitespace, slices to N chars, and
|
|
826
|
-
appends ``" … [+K chars]"`` when truncation actually happened so
|
|
827
|
-
the log self-reports the cut. Empty / missing kind falls back to
|
|
828
|
-
``DEFAULT_TEXT_LIMITS``.
|
|
829
|
-
"""
|
|
830
|
-
if not text:
|
|
831
|
-
return ""
|
|
832
|
-
n = limits.get(kind, DEFAULT_TEXT_LIMITS.get(kind, 0))
|
|
833
|
-
if n <= 0:
|
|
834
|
-
return text
|
|
835
|
-
flat = _WS_RE.sub(" ", text).strip()
|
|
836
|
-
if len(flat) <= n:
|
|
837
|
-
return flat
|
|
838
|
-
return f"{flat[:n]} … [+{len(flat) - n} chars]"
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
def prune_sessions(max_sessions: int = DEFAULT_MAX_SESSIONS, *,
|
|
842
|
-
path: Path | None = None) -> dict[str, Any]:
|
|
843
|
-
"""Keep only the ``max_sessions`` most-recent sessions in the body.
|
|
844
|
-
|
|
845
|
-
Recency is the body line index of a session's last entry — the body
|
|
846
|
-
is append-only, so position is canonical (and stable when multiple
|
|
847
|
-
sessions share a wall-clock second). The trailing ``max_sessions``
|
|
848
|
-
win, the rest of their entries are dropped. Header untouched.
|
|
849
|
-
``<unknown>`` and ``<legacy>`` count as ordinary sessions for the
|
|
850
|
-
purpose of this cap.
|
|
851
|
-
|
|
852
|
-
Returns ``{action, kept_sessions, dropped_sessions, dropped_entries}``.
|
|
853
|
-
Noop when the file is missing, has no body, or carries fewer than
|
|
854
|
-
``max_sessions`` distinct sessions.
|
|
855
|
-
"""
|
|
856
|
-
if max_sessions < 1:
|
|
857
|
-
max_sessions = 1
|
|
858
|
-
p = path or file_path()
|
|
859
|
-
if not p.is_file():
|
|
860
|
-
return {"action": "noop", "kept_sessions": 0,
|
|
861
|
-
"dropped_sessions": 0, "dropped_entries": 0}
|
|
862
|
-
with p.open(encoding="utf-8") as fh:
|
|
863
|
-
lines = fh.readlines()
|
|
864
|
-
if len(lines) <= 1:
|
|
865
|
-
return {"action": "noop", "kept_sessions": 0,
|
|
866
|
-
"dropped_sessions": 0, "dropped_entries": 0}
|
|
867
|
-
header_line = lines[0]
|
|
868
|
-
body = lines[1:]
|
|
869
|
-
# Rank sessions by body position — last appearance wins. Body is
|
|
870
|
-
# append-only, so position is canonical recency; ts is only a
|
|
871
|
-
# secondary signal (tied on second-level resolution in practice).
|
|
872
|
-
last_pos: dict[str, int] = {}
|
|
873
|
-
parsed: list[tuple[str, str]] = [] # (sid, raw_line)
|
|
874
|
-
for idx, line in enumerate(body):
|
|
875
|
-
stripped = line.strip()
|
|
876
|
-
if not stripped:
|
|
877
|
-
continue
|
|
878
|
-
try:
|
|
879
|
-
obj = json.loads(stripped)
|
|
880
|
-
except json.JSONDecodeError:
|
|
881
|
-
parsed.append((SESSION_ID_LEGACY, line))
|
|
882
|
-
last_pos[SESSION_ID_LEGACY] = idx
|
|
883
|
-
continue
|
|
884
|
-
if not isinstance(obj, dict):
|
|
885
|
-
continue
|
|
886
|
-
sid = obj.get("s") if isinstance(obj.get("s"), str) else SESSION_ID_LEGACY
|
|
887
|
-
parsed.append((sid, line))
|
|
888
|
-
last_pos[sid] = idx
|
|
889
|
-
if len(last_pos) <= max_sessions:
|
|
890
|
-
return {"action": "noop", "kept_sessions": len(last_pos),
|
|
891
|
-
"dropped_sessions": 0, "dropped_entries": 0}
|
|
892
|
-
ranked = sorted(last_pos.items(), key=lambda kv: kv[1], reverse=True)
|
|
893
|
-
keep_set = {sid for sid, _ in ranked[:max_sessions]}
|
|
894
|
-
drop_set = {sid for sid, _ in ranked[max_sessions:]}
|
|
895
|
-
kept_lines = [line for sid, line in parsed if sid in keep_set]
|
|
896
|
-
dropped_entries = len(parsed) - len(kept_lines)
|
|
897
|
-
_atomic_write_text(p, header_line + "".join(kept_lines))
|
|
898
|
-
return {"action": "pruned", "kept_sessions": len(keep_set),
|
|
899
|
-
"dropped_sessions": len(drop_set),
|
|
900
|
-
"dropped_entries": dropped_entries}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
def overflow_handle(max_kb: int, mode: str = "rotate", *,
|
|
904
|
-
path: Path | None = None) -> dict[str, Any]:
|
|
905
|
-
"""Enforce max_kb. Returns {'action', 'kept', 'dropped'}.
|
|
906
|
-
|
|
907
|
-
Rotate: drop oldest entries (keep header) until file ≤ max_kb.
|
|
908
|
-
Condense: mark oldest 50% as stale and leave a `needs_condense`
|
|
909
|
-
marker entry for the agent to rewrite on next turn.
|
|
910
|
-
"""
|
|
911
|
-
if mode not in VALID_OVERFLOW:
|
|
912
|
-
raise ValueError(f"mode must be one of {sorted(VALID_OVERFLOW)}")
|
|
913
|
-
p = path or file_path()
|
|
914
|
-
if not p.is_file() or p.stat().st_size <= max_kb * 1024:
|
|
915
|
-
return {"action": "noop", "kept": None, "dropped": 0}
|
|
916
|
-
with p.open(encoding="utf-8") as fh:
|
|
917
|
-
lines = fh.readlines()
|
|
918
|
-
if not lines:
|
|
919
|
-
return {"action": "noop", "kept": 0, "dropped": 0}
|
|
920
|
-
header_line = lines[0]
|
|
921
|
-
entries = lines[1:]
|
|
922
|
-
if mode == "rotate":
|
|
923
|
-
budget = max_kb * 1024 - len(header_line.encode("utf-8"))
|
|
924
|
-
kept: list[str] = []
|
|
925
|
-
total = 0
|
|
926
|
-
for line in reversed(entries):
|
|
927
|
-
size = len(line.encode("utf-8"))
|
|
928
|
-
if total + size > budget:
|
|
929
|
-
break
|
|
930
|
-
kept.append(line)
|
|
931
|
-
total += size
|
|
932
|
-
kept.reverse()
|
|
933
|
-
dropped = len(entries) - len(kept)
|
|
934
|
-
_atomic_write_text(p, header_line + "".join(kept))
|
|
935
|
-
return {"action": "rotate", "kept": len(kept), "dropped": dropped}
|
|
936
|
-
marker = {
|
|
937
|
-
"t": "needs_condense",
|
|
938
|
-
"ts": _now(),
|
|
939
|
-
"reason": f"file exceeded {max_kb} KB, condense-mode requested",
|
|
940
|
-
}
|
|
941
|
-
append(marker, path=p)
|
|
942
|
-
return {"action": "condense_marked", "kept": len(entries), "dropped": 0}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
def hook_append(event: str, *,
|
|
946
|
-
session_id: str | None = None,
|
|
947
|
-
payload: dict[str, Any] | None = None,
|
|
948
|
-
path: Path | None = None,
|
|
949
|
-
settings_path: Path | None = None,
|
|
950
|
-
dry_run: bool = False) -> dict[str, Any]:
|
|
951
|
-
"""Platform-hook entry point — stateless append per session tag.
|
|
952
|
-
|
|
953
|
-
Designed for ``SessionStart``, ``UserPromptSubmit``, ``PostToolUse``,
|
|
954
|
-
``Stop``, ``SessionEnd`` style hooks. Each call derives an ``s`` tag
|
|
955
|
-
from ``session_id`` via :func:`derive_session_tag`; entries from
|
|
956
|
-
different sessions coexist in one file because every body line
|
|
957
|
-
self-identifies. No sidecar, no ownership, no auto-adopt.
|
|
958
|
-
|
|
959
|
-
The first non-disabled call to this function on a missing/empty
|
|
960
|
-
file initialises the v4 header. ``session_start`` is otherwise a
|
|
961
|
-
control-plane noop — useful only as an explicit hint that a new
|
|
962
|
-
session is about to begin (and to trigger pruning of old
|
|
963
|
-
sessions). All other events go through cadence filtering and
|
|
964
|
-
append a body entry whose ``text`` is sliced per
|
|
965
|
-
:func:`_apply_text_limit`.
|
|
966
|
-
|
|
967
|
-
Pruning: when the incoming ``s`` is new (differs from the most
|
|
968
|
-
recent body entry's ``s``), :func:`prune_sessions` runs with
|
|
969
|
-
``chat_history.max_sessions`` so the file never accumulates more
|
|
970
|
-
than the configured number of distinct sessions. The prune is a
|
|
971
|
-
noop when the cap is not reached.
|
|
972
|
-
|
|
973
|
-
Cadence-aware: events that don't match ``chat_history.frequency``
|
|
974
|
-
are silently skipped. ``enabled: false`` short-circuits to a noop.
|
|
975
|
-
|
|
976
|
-
Session-rotation guardrail: when an incoming ``session_start`` (or
|
|
977
|
-
any event) introduces an ``s`` that differs from the most recent
|
|
978
|
-
body entry's ``s`` on a non-empty file, a one-line warning is
|
|
979
|
-
written to stderr so cross-agent setups see the rotation intent
|
|
980
|
-
before it lands. The append still proceeds — the warning is
|
|
981
|
-
advisory, not a block.
|
|
982
|
-
|
|
983
|
-
``dry_run=True`` resolves cadence + entry shape but skips every
|
|
984
|
-
file write (header init, append, prune). The returned dict carries
|
|
985
|
-
``dry_run: True`` plus a ``would_action`` mirroring what the live
|
|
986
|
-
invocation would have reported, and (for events that survive the
|
|
987
|
-
cadence filter) an ``entry_preview`` of the body row that would
|
|
988
|
-
have been written. Smoke tests use this to verify the resolved
|
|
989
|
-
chain without rotating the live session.
|
|
990
|
-
|
|
991
|
-
Returns a structured dict the CLI emits as JSON. Never raises for
|
|
992
|
-
non-fatal control-plane states (cadence skip, disabled,
|
|
993
|
-
unknown-session) — these surface as ``action`` values so hooks
|
|
994
|
-
can choose fail_open vs fail_closed by inspecting the result.
|
|
995
|
-
"""
|
|
996
|
-
if event not in VALID_HOOK_EVENTS:
|
|
997
|
-
raise ValueError(f"event must be one of {sorted(VALID_HOOK_EVENTS)}")
|
|
998
|
-
sp = settings_path or Path(DEFAULT_SETTINGS_FILE)
|
|
999
|
-
if not _read_chat_history_enabled(sp):
|
|
1000
|
-
return {"action": "disabled", "event": event,
|
|
1001
|
-
**({"dry_run": True} if dry_run else {})}
|
|
1002
|
-
p = path or file_path()
|
|
1003
|
-
payload = payload or {}
|
|
1004
|
-
s_tag = derive_session_tag(session_id) if session_id else SESSION_ID_UNKNOWN
|
|
1005
|
-
|
|
1006
|
-
# Detect session rotation BEFORE any header init so the warning
|
|
1007
|
-
# fires against the on-disk state the agent actually sees, not the
|
|
1008
|
-
# post-init state. Empty / missing file → no rotation (nothing to
|
|
1009
|
-
# rotate from); unknown s_tag → no rotation (anonymous appends
|
|
1010
|
-
# can't be attributed to a new session).
|
|
1011
|
-
prior_s = _last_body_session_id(p) if p.is_file() else SESSION_ID_UNKNOWN
|
|
1012
|
-
is_new_session = (
|
|
1013
|
-
s_tag != SESSION_ID_UNKNOWN
|
|
1014
|
-
and prior_s != SESSION_ID_UNKNOWN
|
|
1015
|
-
and prior_s != s_tag
|
|
1016
|
-
)
|
|
1017
|
-
if is_new_session:
|
|
1018
|
-
sys.stderr.write(
|
|
1019
|
-
f"chat-history session_rotation event={event} "
|
|
1020
|
-
f"prior_s={prior_s} new_s={s_tag}\n"
|
|
1021
|
-
)
|
|
1022
|
-
|
|
1023
|
-
# Lazily initialise the v4 header on first use so callers don't
|
|
1024
|
-
# have to invoke `init` separately. Reset is still an explicit
|
|
1025
|
-
# operation via reset_with_entries / clear. When the file already
|
|
1026
|
-
# has a parseable but stale header (v3 in the wild), rewrite the
|
|
1027
|
-
# header in-place — body is preserved, version flips to v4. Without
|
|
1028
|
-
# this branch, v3 headers parse as non-None and the lazy-init path
|
|
1029
|
-
# never fires, leaving the file in a mixed v3-header / v4-body
|
|
1030
|
-
# state forever.
|
|
1031
|
-
if not dry_run:
|
|
1032
|
-
if not p.is_file() or read_header(p) is None:
|
|
1033
|
-
freq = _read_chat_history_frequency(sp)
|
|
1034
|
-
init(freq=freq, path=p)
|
|
1035
|
-
else:
|
|
1036
|
-
migrate_header(p, freq=_read_chat_history_frequency(sp))
|
|
1037
|
-
|
|
1038
|
-
def _maybe_prune() -> None:
|
|
1039
|
-
if dry_run or not is_new_session:
|
|
1040
|
-
return
|
|
1041
|
-
max_n = _read_chat_history_max_sessions(sp)
|
|
1042
|
-
try:
|
|
1043
|
-
prune_sessions(max_n, path=p)
|
|
1044
|
-
except OSError as exc:
|
|
1045
|
-
sys.stderr.write(f"chat-history prune_failed: {exc}\n")
|
|
1046
|
-
|
|
1047
|
-
if event == "session_start":
|
|
1048
|
-
_maybe_prune()
|
|
1049
|
-
action = "session_start_noop"
|
|
1050
|
-
out = {"action": "dry_run" if dry_run else action,
|
|
1051
|
-
"event": event, "s": s_tag}
|
|
1052
|
-
if dry_run:
|
|
1053
|
-
out["would_action"] = action
|
|
1054
|
-
out["dry_run"] = True
|
|
1055
|
-
return out
|
|
1056
|
-
if event == "session_end":
|
|
1057
|
-
_maybe_prune()
|
|
1058
|
-
action = "session_end_noop"
|
|
1059
|
-
out = {"action": "dry_run" if dry_run else action,
|
|
1060
|
-
"event": event, "s": s_tag}
|
|
1061
|
-
if dry_run:
|
|
1062
|
-
out["would_action"] = action
|
|
1063
|
-
out["dry_run"] = True
|
|
1064
|
-
return out
|
|
1065
|
-
|
|
1066
|
-
freq = _read_chat_history_frequency(sp)
|
|
1067
|
-
if event not in CADENCE_EVENTS.get(freq, frozenset()):
|
|
1068
|
-
out = {"action": "skipped_cadence", "event": event,
|
|
1069
|
-
"frequency": freq}
|
|
1070
|
-
if dry_run:
|
|
1071
|
-
out["dry_run"] = True
|
|
1072
|
-
return out
|
|
1073
|
-
|
|
1074
|
-
entry_type = HOOK_EVENT_ENTRY_TYPE.get(event, "agent")
|
|
1075
|
-
limits = _read_text_limits(sp)
|
|
1076
|
-
entry: dict[str, Any] = {"t": entry_type}
|
|
1077
|
-
text = str(payload.get("text", ""))
|
|
1078
|
-
if text:
|
|
1079
|
-
sliced = _apply_text_limit(text, entry_type, limits)
|
|
1080
|
-
if sliced:
|
|
1081
|
-
entry["text"] = sliced
|
|
1082
|
-
if event == "tool_use":
|
|
1083
|
-
tool = payload.get("tool")
|
|
1084
|
-
if tool:
|
|
1085
|
-
entry["tool"] = str(tool)
|
|
1086
|
-
for k in ("agent", "source", "phase", "decision"):
|
|
1087
|
-
if payload.get(k):
|
|
1088
|
-
entry[k] = str(payload[k])
|
|
1089
|
-
if dry_run:
|
|
1090
|
-
preview = dict(entry)
|
|
1091
|
-
preview["s"] = s_tag
|
|
1092
|
-
return {"action": "dry_run", "would_action": "appended",
|
|
1093
|
-
"event": event, "type": entry_type, "s": s_tag,
|
|
1094
|
-
"entry_preview": preview, "dry_run": True}
|
|
1095
|
-
append(entry, path=p, session=s_tag)
|
|
1096
|
-
_maybe_prune()
|
|
1097
|
-
return {"action": "appended", "event": event,
|
|
1098
|
-
"type": entry_type, "s": s_tag}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
def _extract_augment_conversation(
|
|
1102
|
-
payload: dict[str, Any],
|
|
1103
|
-
) -> tuple[str, str]:
|
|
1104
|
-
"""Return ``(user_prompt, agent_response)`` from an Augment payload.
|
|
1105
|
-
|
|
1106
|
-
Augment Code with ``includeConversationData: true`` nests the
|
|
1107
|
-
turn under ``conversation`` (``userPrompt`` + ``agentTextResponse``).
|
|
1108
|
-
Returns empty strings when the block is absent or malformed.
|
|
1109
|
-
"""
|
|
1110
|
-
conv = payload.get("conversation")
|
|
1111
|
-
if not isinstance(conv, dict):
|
|
1112
|
-
return ("", "")
|
|
1113
|
-
user = conv.get("userPrompt")
|
|
1114
|
-
agent = conv.get("agentTextResponse")
|
|
1115
|
-
user_s = user.strip() if isinstance(user, str) else ""
|
|
1116
|
-
agent_s = agent.strip() if isinstance(agent, str) else ""
|
|
1117
|
-
return (user_s, agent_s)
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
def _extract_claude_transcript_response(transcript_path: str) -> str:
|
|
1121
|
-
"""Read Claude Code's JSONL transcript and return the last assistant text.
|
|
1122
|
-
|
|
1123
|
-
Claude Code's ``Stop`` hook payload only carries ``session_id`` and
|
|
1124
|
-
``transcript_path``; the actual response lives inside the JSONL file
|
|
1125
|
-
as a sequence of ``{"type": "assistant", "message": {"content": …}}``
|
|
1126
|
-
entries. Best-effort: silently returns ``""`` on missing file, decode
|
|
1127
|
-
error, or unexpected shape so the caller falls back to other paths.
|
|
1128
|
-
"""
|
|
1129
|
-
if not transcript_path:
|
|
1130
|
-
return ""
|
|
1131
|
-
p = Path(transcript_path)
|
|
1132
|
-
if not p.is_file():
|
|
1133
|
-
return ""
|
|
1134
|
-
last_text = ""
|
|
1135
|
-
try:
|
|
1136
|
-
with p.open(encoding="utf-8") as fh:
|
|
1137
|
-
for line in fh:
|
|
1138
|
-
line = line.strip()
|
|
1139
|
-
if not line:
|
|
1140
|
-
continue
|
|
1141
|
-
try:
|
|
1142
|
-
obj = json.loads(line)
|
|
1143
|
-
except json.JSONDecodeError:
|
|
1144
|
-
continue
|
|
1145
|
-
if not isinstance(obj, dict):
|
|
1146
|
-
continue
|
|
1147
|
-
if obj.get("type") != "assistant":
|
|
1148
|
-
continue
|
|
1149
|
-
msg = obj.get("message")
|
|
1150
|
-
if not isinstance(msg, dict):
|
|
1151
|
-
continue
|
|
1152
|
-
content = msg.get("content")
|
|
1153
|
-
if isinstance(content, str):
|
|
1154
|
-
last_text = content
|
|
1155
|
-
elif isinstance(content, list):
|
|
1156
|
-
parts: list[str] = []
|
|
1157
|
-
for blk in content:
|
|
1158
|
-
if (isinstance(blk, dict)
|
|
1159
|
-
and blk.get("type") == "text"):
|
|
1160
|
-
t = blk.get("text", "")
|
|
1161
|
-
if isinstance(t, str):
|
|
1162
|
-
parts.append(t)
|
|
1163
|
-
if parts:
|
|
1164
|
-
last_text = "\n".join(parts)
|
|
1165
|
-
except OSError:
|
|
1166
|
-
return ""
|
|
1167
|
-
return last_text.strip()
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
def _extract_cursor_text(
|
|
1171
|
-
payload: dict[str, Any], event: str | None,
|
|
1172
|
-
) -> str:
|
|
1173
|
-
"""Cursor hook payload extractor (docs-verified, 2026-05).
|
|
1174
|
-
|
|
1175
|
-
Cursor's ``afterAgentResponse`` and ``stop`` hooks ship a
|
|
1176
|
-
``transcript_path`` pointing at a Claude-format JSONL file (Cursor
|
|
1177
|
-
reuses Claude Code's transcript schema). For ``beforeSubmitPrompt``
|
|
1178
|
-
the prompt is in the top-level ``prompt`` key. The fallback walker
|
|
1179
|
-
handles both, but we route here so the transcript is preferred over
|
|
1180
|
-
any stale top-level field.
|
|
1181
|
-
|
|
1182
|
-
Sources: <https://cursor.com/docs/hooks>,
|
|
1183
|
-
<https://cursor.com/docs/reference/third-party-hooks>.
|
|
1184
|
-
"""
|
|
1185
|
-
if event in ("stop", "agent_response"):
|
|
1186
|
-
tp = payload.get("transcript_path") or payload.get("transcriptPath")
|
|
1187
|
-
if isinstance(tp, str):
|
|
1188
|
-
txt = _extract_claude_transcript_response(tp)
|
|
1189
|
-
if txt:
|
|
1190
|
-
return txt
|
|
1191
|
-
return ""
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
def _extract_cline_text(
|
|
1195
|
-
payload: dict[str, Any], event: str | None,
|
|
1196
|
-
) -> str:
|
|
1197
|
-
"""Cline hook payload extractor (docs-verified, 2026-05).
|
|
1198
|
-
|
|
1199
|
-
Cline ships PascalCase event names (``UserPromptSubmit``,
|
|
1200
|
-
``TaskComplete``) but body keys are camelCase. ``UserPromptSubmit``
|
|
1201
|
-
carries the prompt as ``prompt``; ``TaskComplete`` is mapped to
|
|
1202
|
-
``session_end`` (no body text emitted by default). The top-level
|
|
1203
|
-
fallback already covers ``prompt``, but we route here so future
|
|
1204
|
-
schema extensions land in one place.
|
|
1205
|
-
|
|
1206
|
-
Sources: <https://docs.cline.bot/customization/hooks>,
|
|
1207
|
-
<https://docs.cline.bot/features/hooks>.
|
|
1208
|
-
"""
|
|
1209
|
-
if event == "user_prompt":
|
|
1210
|
-
v = payload.get("prompt") or payload.get("userPrompt")
|
|
1211
|
-
if isinstance(v, str) and v.strip():
|
|
1212
|
-
return v.strip()
|
|
1213
|
-
return ""
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
def _extract_gemini_text(
|
|
1217
|
-
payload: dict[str, Any], event: str | None,
|
|
1218
|
-
) -> str:
|
|
1219
|
-
"""Gemini CLI hook payload extractor (docs-verified, 2026-05).
|
|
1220
|
-
|
|
1221
|
-
Gemini CLI's ``AfterAgent`` payload carries the agent text directly
|
|
1222
|
-
as ``prompt_response`` (snake_case, matching the rest of Gemini's
|
|
1223
|
-
hook keys). When absent, the dispatcher may still receive a
|
|
1224
|
-
``transcript_path`` — Gemini transcripts use the same JSONL shape
|
|
1225
|
-
as Claude, so the Claude walker applies. The top-level fallback
|
|
1226
|
-
does not include ``prompt_response``, which is why this branch is
|
|
1227
|
-
necessary.
|
|
1228
|
-
|
|
1229
|
-
Sources: <https://www.geminicli.com/docs/hooks/>,
|
|
1230
|
-
<https://www.geminicli.com/docs/hooks/reference/>.
|
|
1231
|
-
"""
|
|
1232
|
-
if event in ("agent_response", "stop"):
|
|
1233
|
-
v = payload.get("prompt_response") or payload.get("promptResponse")
|
|
1234
|
-
if isinstance(v, str) and v.strip():
|
|
1235
|
-
return v.strip()
|
|
1236
|
-
tp = payload.get("transcript_path") or payload.get("transcriptPath")
|
|
1237
|
-
if isinstance(tp, str):
|
|
1238
|
-
txt = _extract_claude_transcript_response(tp)
|
|
1239
|
-
if txt:
|
|
1240
|
-
return txt
|
|
1241
|
-
return ""
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
def _extract_windsurf_text(
|
|
1245
|
-
payload: dict[str, Any], event: str | None,
|
|
1246
|
-
) -> str:
|
|
1247
|
-
"""Windsurf hook payload extractor (docs-verified, 2026-05).
|
|
1248
|
-
|
|
1249
|
-
Windsurf has two agent-response variants. ``post_cascade_response``
|
|
1250
|
-
(synchronous) nests the response under ``tool_info.response`` as a
|
|
1251
|
-
markdown string; ``post_cascade_response_with_transcript`` carries
|
|
1252
|
-
a ``transcript_path`` to a JSONL file (Claude-format). The
|
|
1253
|
-
``pre_user_prompt`` event keeps the prompt under the top-level
|
|
1254
|
-
``prompt`` (covered by the fallback).
|
|
1255
|
-
|
|
1256
|
-
Sources: <https://docs.windsurf.com/windsurf/cascade/hooks>.
|
|
1257
|
-
"""
|
|
1258
|
-
if event in ("agent_response", "stop"):
|
|
1259
|
-
info = payload.get("tool_info") or payload.get("toolInfo")
|
|
1260
|
-
if isinstance(info, dict):
|
|
1261
|
-
v = info.get("response") or info.get("text")
|
|
1262
|
-
if isinstance(v, str) and v.strip():
|
|
1263
|
-
return v.strip()
|
|
1264
|
-
tp = payload.get("transcript_path") or payload.get("transcriptPath")
|
|
1265
|
-
if isinstance(tp, str):
|
|
1266
|
-
txt = _extract_claude_transcript_response(tp)
|
|
1267
|
-
if txt:
|
|
1268
|
-
return txt
|
|
1269
|
-
return ""
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
def _extract_hook_text(
|
|
1273
|
-
payload: dict[str, Any],
|
|
1274
|
-
*,
|
|
1275
|
-
platform: str | None = None,
|
|
1276
|
-
event: str | None = None,
|
|
1277
|
-
) -> str:
|
|
1278
|
-
"""Pull a textual snippet out of a platform's hook payload.
|
|
1279
|
-
|
|
1280
|
-
Platform-aware when ``platform`` is supplied: prefers nested keys
|
|
1281
|
-
that the platform documents (Augment ``conversation.*``, Claude Code
|
|
1282
|
-
``transcript_path`` JSONL, Cursor/Gemini/Windsurf docs-verified
|
|
1283
|
-
branches). Falls back to common top-level keys so legacy callers
|
|
1284
|
-
and simple platforms keep working.
|
|
1285
|
-
"""
|
|
1286
|
-
# Augment Code (with includeConversationData: true) — Stop payloads
|
|
1287
|
-
# arrive nested under "conversation".
|
|
1288
|
-
if platform == "augment":
|
|
1289
|
-
user, agent = _extract_augment_conversation(payload)
|
|
1290
|
-
if event == "user_prompt" and user:
|
|
1291
|
-
return user
|
|
1292
|
-
if event in ("stop", "agent_response") and agent:
|
|
1293
|
-
return agent
|
|
1294
|
-
if agent:
|
|
1295
|
-
return agent
|
|
1296
|
-
if user:
|
|
1297
|
-
return user
|
|
1298
|
-
# Claude Code — Stop payload only has transcript_path; parse JSONL
|
|
1299
|
-
# to recover the last assistant message. Cowork (the Claude desktop
|
|
1300
|
-
# app's local-agent-mode runtime) shares the same payload shape, so
|
|
1301
|
-
# the same extractor applies.
|
|
1302
|
-
if platform in ("claude", "cowork") and event in ("stop", "agent_response"):
|
|
1303
|
-
tp = payload.get("transcript_path") or payload.get("transcriptPath")
|
|
1304
|
-
if isinstance(tp, str):
|
|
1305
|
-
txt = _extract_claude_transcript_response(tp)
|
|
1306
|
-
if txt:
|
|
1307
|
-
return txt
|
|
1308
|
-
if platform == "cursor":
|
|
1309
|
-
txt = _extract_cursor_text(payload, event)
|
|
1310
|
-
if txt:
|
|
1311
|
-
return txt
|
|
1312
|
-
if platform == "cline":
|
|
1313
|
-
txt = _extract_cline_text(payload, event)
|
|
1314
|
-
if txt:
|
|
1315
|
-
return txt
|
|
1316
|
-
if platform == "gemini":
|
|
1317
|
-
txt = _extract_gemini_text(payload, event)
|
|
1318
|
-
if txt:
|
|
1319
|
-
return txt
|
|
1320
|
-
if platform == "windsurf":
|
|
1321
|
-
txt = _extract_windsurf_text(payload, event)
|
|
1322
|
-
if txt:
|
|
1323
|
-
return txt
|
|
1324
|
-
for key in ("prompt", "user_prompt", "first_user_msg", "firstUserMsg",
|
|
1325
|
-
"userMessage", "user_message", "text", "response", "message",
|
|
1326
|
-
"content"):
|
|
1327
|
-
v = payload.get(key)
|
|
1328
|
-
if isinstance(v, str) and v.strip():
|
|
1329
|
-
return v.strip()
|
|
1330
|
-
# Tool response wrappers (Claude PostToolUse, etc.) — best-effort.
|
|
1331
|
-
tr = payload.get("tool_response") or payload.get("toolResponse")
|
|
1332
|
-
if isinstance(tr, dict):
|
|
1333
|
-
for key in ("output", "stdout", "result", "text"):
|
|
1334
|
-
v = tr.get(key)
|
|
1335
|
-
if isinstance(v, str) and v.strip():
|
|
1336
|
-
return v.strip()
|
|
1337
|
-
return ""
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
def _extract_hook_tool(payload: dict[str, Any]) -> str:
|
|
1341
|
-
"""Pull the tool name out of a platform's hook payload."""
|
|
1342
|
-
for key in ("tool_name", "toolName", "tool"):
|
|
1343
|
-
v = payload.get(key)
|
|
1344
|
-
if isinstance(v, str) and v.strip():
|
|
1345
|
-
return v.strip()
|
|
1346
|
-
return ""
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
def _extract_hook_event(payload: dict[str, Any]) -> str:
|
|
1350
|
-
"""Pull the platform's native hook event name out of the payload."""
|
|
1351
|
-
for key in ("hook_event_name", "event", "eventName", "event_name"):
|
|
1352
|
-
v = payload.get(key)
|
|
1353
|
-
if isinstance(v, str) and v.strip():
|
|
1354
|
-
return v.strip()
|
|
1355
|
-
return ""
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
def _extract_session_id(payload: dict[str, Any]) -> str:
|
|
1359
|
-
"""Pull a stable session identifier out of a platform's hook payload.
|
|
1360
|
-
|
|
1361
|
-
Used by hook_dispatch as a fallback first-user-msg source on
|
|
1362
|
-
platforms whose SessionStart payload does not include the user
|
|
1363
|
-
prompt (notably Augment Code).
|
|
1364
|
-
"""
|
|
1365
|
-
for key in ("session_id", "sessionId", "task_id", "taskId",
|
|
1366
|
-
"conversation_id", "conversationId"):
|
|
1367
|
-
v = payload.get(key)
|
|
1368
|
-
if isinstance(v, str) and v.strip():
|
|
1369
|
-
return v.strip()
|
|
1370
|
-
return ""
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
def hook_dispatch(platform: str, raw_json: str, *,
|
|
1374
|
-
event_override: str | None = None,
|
|
1375
|
-
path: Path | None = None,
|
|
1376
|
-
settings_path: Path | None = None,
|
|
1377
|
-
dry_run: bool = False) -> dict[str, Any]:
|
|
1378
|
-
"""Read a platform's stdin JSON, translate to our hook vocabulary, dispatch.
|
|
1379
|
-
|
|
1380
|
-
Used by ``chat_history.py hook-dispatch --platform <name>`` so
|
|
1381
|
-
consumer projects can wire their per-platform hook config to a
|
|
1382
|
-
single command. The mapping comes from ``PLATFORM_EVENT_MAP``;
|
|
1383
|
-
unmapped events are silently skipped (returned as
|
|
1384
|
-
``skipped_unmapped_event``).
|
|
1385
|
-
|
|
1386
|
-
Schema v4: every dispatch extracts the platform's stable
|
|
1387
|
-
``session_id`` from the payload and forwards it to
|
|
1388
|
-
:func:`hook_append`, where :func:`derive_session_tag` produces the
|
|
1389
|
-
16-char ``s`` tag carried on every body entry. No sidecar, no
|
|
1390
|
-
ownership, no auto-adopt — multi-session coexistence is implicit
|
|
1391
|
-
via the ``s`` field.
|
|
1392
|
-
|
|
1393
|
-
``dry_run=True`` propagates to :func:`hook_append` so the resolved
|
|
1394
|
-
chain (platform → raw_event → mapped event → cadence) is reported
|
|
1395
|
-
without writing the live history file.
|
|
1396
|
-
"""
|
|
1397
|
-
if platform not in PLATFORM_EVENT_MAP:
|
|
1398
|
-
raise ValueError(
|
|
1399
|
-
f"unknown platform: {platform!r}; "
|
|
1400
|
-
f"expected one of {sorted(VALID_PLATFORMS)}"
|
|
1401
|
-
)
|
|
1402
|
-
raw = (raw_json or "").strip()
|
|
1403
|
-
if not raw:
|
|
1404
|
-
payload: dict[str, Any] = {}
|
|
1405
|
-
else:
|
|
1406
|
-
try:
|
|
1407
|
-
payload = json.loads(raw)
|
|
1408
|
-
except json.JSONDecodeError as exc:
|
|
1409
|
-
raise ValueError(f"invalid JSON on stdin: {exc}") from exc
|
|
1410
|
-
if not isinstance(payload, dict):
|
|
1411
|
-
raise ValueError("stdin JSON must decode to an object")
|
|
1412
|
-
|
|
1413
|
-
# Unwrap dispatcher envelope (Phase 7.3, hook-architecture-v1.md). When
|
|
1414
|
-
# the dispatcher invoked us, stdin carries {schema_version, platform,
|
|
1415
|
-
# event, payload, …}; pull the platform-native data out of `payload`
|
|
1416
|
-
# and let the envelope's `event` override the per-platform mapping.
|
|
1417
|
-
envelope_event = ""
|
|
1418
|
-
if all(k in payload for k in ("schema_version", "platform", "event", "payload")):
|
|
1419
|
-
envelope_event = (payload.get("native_event") or payload.get("event") or "").strip()
|
|
1420
|
-
inner = payload.get("payload")
|
|
1421
|
-
payload = inner if isinstance(inner, dict) else {}
|
|
1422
|
-
|
|
1423
|
-
raw_event = (event_override or envelope_event or _extract_hook_event(payload) or "").strip()
|
|
1424
|
-
event = PLATFORM_EVENT_MAP[platform].get(raw_event)
|
|
1425
|
-
if not event:
|
|
1426
|
-
return {"action": "skipped_unmapped_event", "platform": platform,
|
|
1427
|
-
"raw_event": raw_event}
|
|
1428
|
-
|
|
1429
|
-
text = _extract_hook_text(payload, platform=platform, event=event)
|
|
1430
|
-
tool = _extract_hook_tool(payload)
|
|
1431
|
-
session_id = _extract_session_id(payload)
|
|
1432
|
-
|
|
1433
|
-
# Augment dual-emit: with includeConversationData: true the Stop
|
|
1434
|
-
# payload carries both the user prompt and the agent response in one
|
|
1435
|
-
# call (Augment has no UserPromptSubmit equivalent). Synthesize a
|
|
1436
|
-
# user_prompt append before the stop append so both sides land in
|
|
1437
|
-
# history under the active cadence.
|
|
1438
|
-
augment_user_prompt = ""
|
|
1439
|
-
if platform == "augment" and event == "stop":
|
|
1440
|
-
u, _a = _extract_augment_conversation(payload)
|
|
1441
|
-
augment_user_prompt = u
|
|
1442
|
-
|
|
1443
|
-
hook_payload: dict[str, Any] = {
|
|
1444
|
-
"source": f"hook:{platform}:{raw_event}",
|
|
1445
|
-
"agent": platform,
|
|
1446
|
-
}
|
|
1447
|
-
if text and event != "session_start":
|
|
1448
|
-
hook_payload["text"] = text
|
|
1449
|
-
if tool:
|
|
1450
|
-
hook_payload["tool"] = tool
|
|
1451
|
-
|
|
1452
|
-
if augment_user_prompt:
|
|
1453
|
-
hook_append(
|
|
1454
|
-
"user_prompt",
|
|
1455
|
-
session_id=session_id,
|
|
1456
|
-
payload={
|
|
1457
|
-
"text": augment_user_prompt,
|
|
1458
|
-
"source": f"hook:{platform}:{raw_event}:user",
|
|
1459
|
-
"agent": platform,
|
|
1460
|
-
},
|
|
1461
|
-
path=path, settings_path=settings_path,
|
|
1462
|
-
dry_run=dry_run,
|
|
1463
|
-
)
|
|
1464
|
-
|
|
1465
|
-
return hook_append(event, session_id=session_id, payload=hook_payload,
|
|
1466
|
-
path=path, settings_path=settings_path,
|
|
1467
|
-
dry_run=dry_run)
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
def _cmd_init(args) -> int:
|
|
1471
|
-
h = init(freq=args.freq)
|
|
1472
|
-
print(json.dumps(h, ensure_ascii=False))
|
|
1473
|
-
return 0
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
def _cmd_hook_append(args) -> int:
|
|
1477
|
-
payload: dict[str, Any] = {}
|
|
1478
|
-
if args.payload:
|
|
1479
|
-
try:
|
|
1480
|
-
payload = json.loads(args.payload)
|
|
1481
|
-
except json.JSONDecodeError as exc:
|
|
1482
|
-
print(f"error: --payload must be valid JSON: {exc}",
|
|
1483
|
-
file=sys.stderr)
|
|
1484
|
-
return EXIT_BAD_ARGS
|
|
1485
|
-
if not isinstance(payload, dict):
|
|
1486
|
-
print("error: --payload must decode to a JSON object",
|
|
1487
|
-
file=sys.stderr)
|
|
1488
|
-
return EXIT_BAD_ARGS
|
|
1489
|
-
settings_path = Path(args.settings) if args.settings else None
|
|
1490
|
-
try:
|
|
1491
|
-
result = hook_append(
|
|
1492
|
-
args.event,
|
|
1493
|
-
session_id=args.session_id,
|
|
1494
|
-
payload=payload,
|
|
1495
|
-
settings_path=settings_path,
|
|
1496
|
-
dry_run=getattr(args, "dry_run", False),
|
|
1497
|
-
)
|
|
1498
|
-
except ValueError as exc:
|
|
1499
|
-
print(f"error: {exc}", file=sys.stderr)
|
|
1500
|
-
return EXIT_BAD_ARGS
|
|
1501
|
-
print(json.dumps(result, ensure_ascii=False))
|
|
1502
|
-
return EXIT_OK
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
def _cmd_hook_dispatch(args) -> int:
|
|
1506
|
-
raw = sys.stdin.read() if not sys.stdin.isatty() else ""
|
|
1507
|
-
settings_path = Path(args.settings) if args.settings else None
|
|
1508
|
-
try:
|
|
1509
|
-
result = hook_dispatch(
|
|
1510
|
-
args.platform,
|
|
1511
|
-
raw,
|
|
1512
|
-
event_override=args.event,
|
|
1513
|
-
settings_path=settings_path,
|
|
1514
|
-
dry_run=getattr(args, "dry_run", False),
|
|
1515
|
-
)
|
|
1516
|
-
except ValueError as exc:
|
|
1517
|
-
print(f"error: {exc}", file=sys.stderr)
|
|
1518
|
-
return EXIT_BAD_ARGS
|
|
1519
|
-
print(json.dumps(result, ensure_ascii=False))
|
|
1520
|
-
return EXIT_OK
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
def _cmd_append(args) -> int:
|
|
1524
|
-
entry = json.loads(args.json) if args.json else {}
|
|
1525
|
-
entry.setdefault("t", args.type)
|
|
1526
|
-
if not entry.get("t"):
|
|
1527
|
-
print("error: --type or a 't' key in --json is required",
|
|
1528
|
-
file=sys.stderr)
|
|
1529
|
-
return EXIT_BAD_ARGS
|
|
1530
|
-
session = derive_session_tag(args.session_id) if args.session_id else None
|
|
1531
|
-
append(entry, session=session)
|
|
1532
|
-
return EXIT_OK
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
def _cmd_status(_args) -> int:
|
|
1536
|
-
print(json.dumps(status(), ensure_ascii=False, indent=2))
|
|
1537
|
-
return 0
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
def _load_entries_arg(args) -> list[dict[str, Any]]:
|
|
1541
|
-
if getattr(args, "entries_stdin", False):
|
|
1542
|
-
raw = sys.stdin.read()
|
|
1543
|
-
else:
|
|
1544
|
-
raw = args.entries_json or "[]"
|
|
1545
|
-
try:
|
|
1546
|
-
data = json.loads(raw)
|
|
1547
|
-
except json.JSONDecodeError as exc:
|
|
1548
|
-
raise ValueError(f"invalid JSON for entries: {exc}") from exc
|
|
1549
|
-
if not isinstance(data, list):
|
|
1550
|
-
raise ValueError("entries must be a JSON array")
|
|
1551
|
-
return data
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
def _cmd_reset(args) -> int:
|
|
1555
|
-
entries = _load_entries_arg(args)
|
|
1556
|
-
h = reset_with_entries(entries, freq=args.freq)
|
|
1557
|
-
print(json.dumps(h, ensure_ascii=False))
|
|
1558
|
-
return 0
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
def _cmd_prune_sessions(args) -> int:
|
|
1562
|
-
settings_path = Path(args.settings) if args.settings else None
|
|
1563
|
-
if args.max_sessions is not None:
|
|
1564
|
-
max_n = max(1, int(args.max_sessions))
|
|
1565
|
-
else:
|
|
1566
|
-
sp = settings_path or Path(DEFAULT_SETTINGS_FILE)
|
|
1567
|
-
max_n = _read_chat_history_max_sessions(sp)
|
|
1568
|
-
result = prune_sessions(max_n)
|
|
1569
|
-
print(json.dumps(result, ensure_ascii=False))
|
|
1570
|
-
return EXIT_OK
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
def _cmd_prepend(args) -> int:
|
|
1574
|
-
entries = _load_entries_arg(args)
|
|
1575
|
-
n = prepend_entries(entries)
|
|
1576
|
-
print(json.dumps({"prepended": n}, ensure_ascii=False))
|
|
1577
|
-
return 0
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
def _cmd_clear(_args) -> int:
|
|
1581
|
-
clear()
|
|
1582
|
-
return 0
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
def _cmd_read(args) -> int:
|
|
1586
|
-
last = None if args.all else args.last
|
|
1587
|
-
agent = args.agent
|
|
1588
|
-
if args.all:
|
|
1589
|
-
entries = read_entries(last=last, session=None, agent=agent)
|
|
1590
|
-
elif args.session is not None:
|
|
1591
|
-
entries = read_entries(last=last, session=args.session, agent=agent)
|
|
1592
|
-
elif agent is not None:
|
|
1593
|
-
# Agent filter without --session implies "across the most recent
|
|
1594
|
-
# session"; honour the current-session scope of the default
|
|
1595
|
-
# `read` semantics so the filter narrows, never widens.
|
|
1596
|
-
sid = _last_body_session_id(file_path())
|
|
1597
|
-
entries = read_entries(last=last, session=sid, agent=agent)
|
|
1598
|
-
else:
|
|
1599
|
-
entries = read_entries_for_current(last=last)
|
|
1600
|
-
print(json.dumps(entries, ensure_ascii=False, indent=2))
|
|
1601
|
-
return 0
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
def _cmd_sessions(args) -> int:
|
|
1605
|
-
sessions = list_sessions(summary=args.summary)
|
|
1606
|
-
if not args.include_empty:
|
|
1607
|
-
sessions = [s for s in sessions if s["count"] > 0]
|
|
1608
|
-
sessions = sessions[: args.limit]
|
|
1609
|
-
if args.json:
|
|
1610
|
-
print(json.dumps(sessions, ensure_ascii=False, indent=2))
|
|
1611
|
-
return 0
|
|
1612
|
-
if not sessions:
|
|
1613
|
-
print("(no sessions)")
|
|
1614
|
-
return 0
|
|
1615
|
-
last_col = "SUMMARY" if args.summary else "PREVIEW"
|
|
1616
|
-
rows = [("ID", "COUNT", "AGENTS", "LAST_TS", last_col)]
|
|
1617
|
-
for s in sessions:
|
|
1618
|
-
last_val = s.get("summary") if args.summary else s.get("preview")
|
|
1619
|
-
agents_val = ",".join(s.get("agents") or []) or "-"
|
|
1620
|
-
rows.append((
|
|
1621
|
-
s["id"],
|
|
1622
|
-
str(s["count"]),
|
|
1623
|
-
agents_val,
|
|
1624
|
-
s["last_ts"] or "-",
|
|
1625
|
-
last_val or "-",
|
|
1626
|
-
))
|
|
1627
|
-
widths = [max(len(r[i]) for r in rows) for i in range(5)]
|
|
1628
|
-
for i, r in enumerate(rows):
|
|
1629
|
-
line = " ".join(r[j].ljust(widths[j]) for j in range(5))
|
|
1630
|
-
print(line)
|
|
1631
|
-
if i == 0:
|
|
1632
|
-
print(" ".join("-" * widths[j] for j in range(5)))
|
|
1633
|
-
return 0
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
def _cmd_rotate(args) -> int:
|
|
1637
|
-
result = overflow_handle(args.max_kb, mode=args.mode)
|
|
1638
|
-
print(json.dumps(result, ensure_ascii=False))
|
|
1639
|
-
return 0
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
def main(argv: list[str] | None = None) -> int:
|
|
1643
|
-
ap = argparse.ArgumentParser(description=__doc__)
|
|
1644
|
-
sub = ap.add_subparsers(dest="cmd", required=True)
|
|
1645
|
-
p_init = sub.add_parser("init")
|
|
1646
|
-
p_init.add_argument("--freq", default="per_phase", choices=sorted(VALID_FREQS))
|
|
1647
|
-
p_init.set_defaults(func=_cmd_init)
|
|
1648
|
-
p_app = sub.add_parser("append")
|
|
1649
|
-
p_app.add_argument("--type", help="entry type (t field)")
|
|
1650
|
-
p_app.add_argument("--json", help="JSON object with entry fields")
|
|
1651
|
-
p_app.add_argument(
|
|
1652
|
-
"--session-id",
|
|
1653
|
-
default=None,
|
|
1654
|
-
help=("platform session id; hashed to derive the body 's' tag. "
|
|
1655
|
-
"Omit to write entries with s=<unknown>."),
|
|
1656
|
-
)
|
|
1657
|
-
p_app.set_defaults(func=_cmd_append)
|
|
1658
|
-
sub.add_parser("status").set_defaults(func=_cmd_status)
|
|
1659
|
-
p_reset = sub.add_parser("reset")
|
|
1660
|
-
p_reset.add_argument("--freq", default="per_phase",
|
|
1661
|
-
choices=sorted(VALID_FREQS))
|
|
1662
|
-
g_r = p_reset.add_mutually_exclusive_group(required=True)
|
|
1663
|
-
g_r.add_argument("--entries-json",
|
|
1664
|
-
help="JSON array of entry dicts")
|
|
1665
|
-
g_r.add_argument("--entries-stdin", action="store_true",
|
|
1666
|
-
help="read JSON array from stdin")
|
|
1667
|
-
p_reset.set_defaults(func=_cmd_reset)
|
|
1668
|
-
p_prune = sub.add_parser(
|
|
1669
|
-
"prune-sessions",
|
|
1670
|
-
help=("keep only the N most-recent sessions in the body; "
|
|
1671
|
-
"N defaults to chat_history.max_sessions"),
|
|
1672
|
-
)
|
|
1673
|
-
p_prune.add_argument(
|
|
1674
|
-
"--max-sessions",
|
|
1675
|
-
type=int,
|
|
1676
|
-
default=None,
|
|
1677
|
-
help=f"max distinct sessions to keep (default: settings or {DEFAULT_MAX_SESSIONS})",
|
|
1678
|
-
)
|
|
1679
|
-
p_prune.add_argument(
|
|
1680
|
-
"--settings",
|
|
1681
|
-
default=None,
|
|
1682
|
-
help=f"path to agent settings (default: {DEFAULT_SETTINGS_FILE})",
|
|
1683
|
-
)
|
|
1684
|
-
p_prune.set_defaults(func=_cmd_prune_sessions)
|
|
1685
|
-
p_prep = sub.add_parser("prepend")
|
|
1686
|
-
g_p = p_prep.add_mutually_exclusive_group(required=True)
|
|
1687
|
-
g_p.add_argument("--entries-json",
|
|
1688
|
-
help="JSON array of entry dicts")
|
|
1689
|
-
g_p.add_argument("--entries-stdin", action="store_true",
|
|
1690
|
-
help="read JSON array from stdin")
|
|
1691
|
-
p_prep.set_defaults(func=_cmd_prepend)
|
|
1692
|
-
sub.add_parser("clear").set_defaults(func=_cmd_clear)
|
|
1693
|
-
p_read = sub.add_parser("read")
|
|
1694
|
-
grp = p_read.add_mutually_exclusive_group()
|
|
1695
|
-
grp.add_argument("--last", type=int, default=5,
|
|
1696
|
-
help="return the trailing N entries (default: 5)")
|
|
1697
|
-
grp.add_argument("--all", action="store_true",
|
|
1698
|
-
help="return all entries (across all sessions)")
|
|
1699
|
-
p_read.add_argument(
|
|
1700
|
-
"--session", default=None,
|
|
1701
|
-
help=("filter to entries with this session tag "
|
|
1702
|
-
"(16-char sha256(session_id), '<legacy>', or '<unknown>'); "
|
|
1703
|
-
"defaults to the most recent session"),
|
|
1704
|
-
)
|
|
1705
|
-
p_read.add_argument(
|
|
1706
|
-
"--agent", default=None,
|
|
1707
|
-
help=("filter to entries whose body 'agent' field matches "
|
|
1708
|
-
f"(exact match; use '{AGENT_UNKNOWN}' for unattributed "
|
|
1709
|
-
"entries). When --session is omitted, the filter applies "
|
|
1710
|
-
"to the most recent session."),
|
|
1711
|
-
)
|
|
1712
|
-
p_read.set_defaults(func=_cmd_read)
|
|
1713
|
-
p_sess = sub.add_parser("sessions")
|
|
1714
|
-
p_sess.add_argument("--limit", type=int, default=20,
|
|
1715
|
-
help="max non-empty sessions to print (default: 20)")
|
|
1716
|
-
p_sess.add_argument("--include-empty", action="store_true",
|
|
1717
|
-
help="include sessions with zero body entries")
|
|
1718
|
-
p_sess.add_argument("--json", action="store_true",
|
|
1719
|
-
help="emit JSON instead of a human-readable table")
|
|
1720
|
-
p_sess.add_argument("--summary", action="store_true",
|
|
1721
|
-
help=("include a head-5 + tail-5 sampled summary "
|
|
1722
|
-
"(max 10 entries) per session — token-cheap "
|
|
1723
|
-
"alternative to the bare preview"))
|
|
1724
|
-
p_sess.set_defaults(func=_cmd_sessions)
|
|
1725
|
-
p_rot = sub.add_parser("rotate")
|
|
1726
|
-
p_rot.add_argument("--max-kb", type=int, default=256)
|
|
1727
|
-
p_rot.add_argument("--mode", default="rotate", choices=sorted(VALID_OVERFLOW))
|
|
1728
|
-
p_rot.set_defaults(func=_cmd_rotate)
|
|
1729
|
-
p_hook = sub.add_parser(
|
|
1730
|
-
"hook-append",
|
|
1731
|
-
help=("platform-hook entry point — stateless append per session; "
|
|
1732
|
-
"derives the body 's' tag from --session-id"),
|
|
1733
|
-
)
|
|
1734
|
-
p_hook.add_argument(
|
|
1735
|
-
"--event",
|
|
1736
|
-
required=True,
|
|
1737
|
-
choices=sorted(VALID_HOOK_EVENTS),
|
|
1738
|
-
help="hook event name",
|
|
1739
|
-
)
|
|
1740
|
-
p_hook.add_argument(
|
|
1741
|
-
"--session-id",
|
|
1742
|
-
default=None,
|
|
1743
|
-
help=("platform session id; hashed to derive the body 's' tag. "
|
|
1744
|
-
"Omit to write entries with s=<unknown>."),
|
|
1745
|
-
)
|
|
1746
|
-
p_hook.add_argument(
|
|
1747
|
-
"--payload",
|
|
1748
|
-
default=None,
|
|
1749
|
-
help=("JSON object with event-specific fields "
|
|
1750
|
-
"(text/tool/source/phase/decision)"),
|
|
1751
|
-
)
|
|
1752
|
-
p_hook.add_argument(
|
|
1753
|
-
"--settings",
|
|
1754
|
-
default=None,
|
|
1755
|
-
help=f"path to agent settings (default: {DEFAULT_SETTINGS_FILE})",
|
|
1756
|
-
)
|
|
1757
|
-
p_hook.add_argument(
|
|
1758
|
-
"--dry-run",
|
|
1759
|
-
action="store_true",
|
|
1760
|
-
help=("resolve cadence + entry shape and print the plan; "
|
|
1761
|
-
"skip every file write (header init, append, prune)"),
|
|
1762
|
-
)
|
|
1763
|
-
p_hook.set_defaults(func=_cmd_hook_append)
|
|
1764
|
-
p_disp = sub.add_parser(
|
|
1765
|
-
"hook-dispatch",
|
|
1766
|
-
help=("platform-hook entry point — reads platform JSON from stdin, "
|
|
1767
|
-
"translates the native event name to our vocabulary, and "
|
|
1768
|
-
"invokes hook-append"),
|
|
1769
|
-
)
|
|
1770
|
-
p_disp.add_argument(
|
|
1771
|
-
"--platform",
|
|
1772
|
-
required=True,
|
|
1773
|
-
choices=sorted(VALID_PLATFORMS),
|
|
1774
|
-
help="source platform whose hook is firing",
|
|
1775
|
-
)
|
|
1776
|
-
p_disp.add_argument(
|
|
1777
|
-
"--event",
|
|
1778
|
-
default=None,
|
|
1779
|
-
help=("override the platform-native event name (default: read "
|
|
1780
|
-
"from stdin payload key hook_event_name / event)"),
|
|
1781
|
-
)
|
|
1782
|
-
p_disp.add_argument(
|
|
1783
|
-
"--settings",
|
|
1784
|
-
default=None,
|
|
1785
|
-
help=f"path to agent settings (default: {DEFAULT_SETTINGS_FILE})",
|
|
1786
|
-
)
|
|
1787
|
-
p_disp.add_argument(
|
|
1788
|
-
"--dry-run",
|
|
1789
|
-
action="store_true",
|
|
1790
|
-
help=("resolve platform → event → cadence chain and print the "
|
|
1791
|
-
"plan; skip every file write (no header, no body row)"),
|
|
1792
|
-
)
|
|
1793
|
-
p_disp.set_defaults(func=_cmd_hook_dispatch)
|
|
1794
|
-
args = ap.parse_args(argv)
|
|
1795
|
-
return args.func(args)
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
if __name__ == "__main__":
|
|
1799
|
-
sys.exit(main())
|