@event4u/agent-config 9.9.0 → 9.10.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.
Files changed (384) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +153 -194
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/agent-status.md +12 -11
  5. package/dist/agent-src/commands/agents/user/accept.md +115 -30
  6. package/dist/agent-src/commands/agents/user/delete.md +147 -0
  7. package/dist/agent-src/commands/agents/user/review.md +65 -28
  8. package/dist/agent-src/commands/agents/user/show.md +82 -29
  9. package/dist/agent-src/commands/agents/user/update.md +2 -2
  10. package/dist/agent-src/commands/agents/user.md +16 -3
  11. package/dist/agent-src/commands/check-current-md.md +0 -10
  12. package/dist/agent-src/commands/condense.md +28 -97
  13. package/dist/agent-src/commands/cost/report.md +7 -0
  14. package/dist/agent-src/commands/fix/portability.md +0 -8
  15. package/dist/agent-src/commands/fix/refs.md +0 -8
  16. package/dist/agent-src/commands/humanize.md +2 -2
  17. package/dist/agent-src/commands/jira-ticket.md +1 -1
  18. package/dist/agent-src/commands/memory/load.md +11 -0
  19. package/dist/agent-src/commands/optimize/skills.md +1 -1
  20. package/dist/agent-src/commands/pr/create.md +4 -4
  21. package/dist/agent-src/commands/profile/show.md +3 -3
  22. package/dist/agent-src/commands/rule-compliance-audit.md +5 -4
  23. package/dist/agent-src/commands/security-audit-config.md +1 -1
  24. package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
  25. package/dist/agent-src/commands/tdd.md +21 -0
  26. package/dist/agent-src/commands/team/delegate.md +2 -2
  27. package/dist/agent-src/commands/team-knowledge/bootstrap.md +9 -8
  28. package/dist/agent-src/commands/team-knowledge/consolidate.md +8 -7
  29. package/dist/agent-src/commands/team.md +4 -1
  30. package/dist/agent-src/commands/upstream-contribute.md +0 -1
  31. package/dist/agent-src/contexts/authority/commit-mechanics.md +7 -0
  32. package/dist/agent-src/contexts/authority/destructive-mechanics.md +16 -0
  33. package/dist/agent-src/contexts/authority/scope-mechanics.md +61 -0
  34. package/dist/agent-src/contexts/communication/rules-auto/reply-close-mechanics.md +20 -18
  35. package/dist/agent-src/contexts/communication/rules-auto/skill-quality-mechanics.md +1 -1
  36. package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -1
  37. package/dist/agent-src/contexts/communication/rules-auto/source-of-truth-mechanics.md +9 -10
  38. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +1 -1
  39. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +11 -0
  40. package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +26 -15
  41. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -0
  42. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +67 -37
  43. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  44. package/dist/agent-src/contexts/execution/autonomy-examples.md +1 -1
  45. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +7 -6
  46. package/dist/agent-src/contexts/execution/evidence-discipline.md +92 -77
  47. package/dist/agent-src/contexts/execution/orchestration-benchmark-gate.md +22 -21
  48. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +24 -0
  49. package/dist/agent-src/contexts/execution/project-intelligence.md +122 -103
  50. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +23 -21
  51. package/dist/agent-src/contexts/execution/subagent-response-contract.md +5 -5
  52. package/dist/agent-src/contexts/execution/subagent-routing.md +11 -0
  53. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +13 -13
  54. package/dist/agent-src/contexts/execution/subagent-steering.md +36 -34
  55. package/dist/agent-src/contexts/execution/toolchain-resolver.md +1 -1
  56. package/dist/agent-src/contexts/execution/user-memory-channels.md +189 -0
  57. package/dist/agent-src/contexts/execution/verification-mechanics.md +9 -0
  58. package/dist/agent-src/contexts/model-recommendations.md +3 -2
  59. package/dist/agent-src/contexts/subagent-configuration.md +3 -3
  60. package/dist/agent-src/ghostwriter/README.md +2 -2
  61. package/dist/agent-src/packs/README.md +1 -1
  62. package/dist/agent-src/personas/README.md +5 -5
  63. package/dist/agent-src/personas/_template-specialist/persona.md +3 -3
  64. package/dist/agent-src/personas/backend-architect.md +24 -23
  65. package/dist/agent-src/personas/eloquent-tamer.md +30 -30
  66. package/dist/agent-src/personas/frontend-engineer.md +30 -30
  67. package/dist/agent-src/personas/product-owner.md +41 -38
  68. package/dist/agent-src/personas/qa.md +13 -13
  69. package/dist/agent-src/personas/security-engineer.md +22 -22
  70. package/dist/agent-src/presets/README.md +3 -3
  71. package/dist/agent-src/profiles/README.md +3 -3
  72. package/dist/agent-src/rules/active-remediation.md +2 -2
  73. package/dist/agent-src/rules/artifact-engagement-recording.md +4 -4
  74. package/dist/agent-src/rules/ask-when-uncertain.md +0 -4
  75. package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
  76. package/dist/agent-src/rules/broken-access-control.md +4 -4
  77. package/dist/agent-src/rules/code-comment-discipline.md +1 -1
  78. package/dist/agent-src/rules/code-provenance.md +2 -2
  79. package/dist/agent-src/rules/commit-policy.md +4 -9
  80. package/dist/agent-src/rules/communication-through-line.md +5 -5
  81. package/dist/agent-src/rules/decision-revisit-gate.md +1 -1
  82. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
  83. package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
  84. package/dist/agent-src/rules/domain-safety-pii.md +1 -1
  85. package/dist/agent-src/rules/external-code-graph-interop.md +1 -1
  86. package/dist/agent-src/rules/fast-path-marker-visibility.md +43 -7
  87. package/dist/agent-src/rules/finance-safety-floor.md +1 -1
  88. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +3 -3
  89. package/dist/agent-src/rules/history-discipline.md +1 -1
  90. package/dist/agent-src/rules/legal-safety-floor.md +1 -1
  91. package/dist/agent-src/rules/lethal-trifecta-guard.md +5 -5
  92. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +10 -8
  93. package/dist/agent-src/rules/media-governance-routing.md +13 -13
  94. package/dist/agent-src/rules/media-sync-ground-truth.md +29 -11
  95. package/dist/agent-src/rules/no-cheap-questions.md +7 -7
  96. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +29 -18
  97. package/dist/agent-src/rules/non-destructive-by-default.md +5 -23
  98. package/dist/agent-src/rules/onboarding-gate.md +14 -4
  99. package/dist/agent-src/rules/persona-governance.md +2 -2
  100. package/dist/agent-src/rules/prefer-enums-over-literals.md +9 -9
  101. package/dist/agent-src/rules/preservation-guard.md +10 -2
  102. package/dist/agent-src/rules/question-not-instruction.md +1 -1
  103. package/dist/agent-src/rules/roadmap-progress-sync.md +6 -6
  104. package/dist/agent-src/rules/rule-type-governance.md +1 -1
  105. package/dist/agent-src/rules/scale-discipline.md +1 -1
  106. package/dist/agent-src/rules/scope-control.md +1 -1
  107. package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
  108. package/dist/agent-src/rules/security-sensitive-stop.md +17 -11
  109. package/dist/agent-src/rules/senior-engineering-discipline.md +17 -17
  110. package/dist/agent-src/rules/session-canary.md +1 -1
  111. package/dist/agent-src/rules/skill-quality.md +1 -1
  112. package/dist/agent-src/rules/source-confidentiality.md +21 -19
  113. package/dist/agent-src/rules/source-of-truth.md +6 -5
  114. package/dist/agent-src/rules/spreadsheet-source-quality.md +2 -2
  115. package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
  116. package/dist/agent-src/rules/think-before-action.md +5 -5
  117. package/dist/agent-src/rules/token-budget-discipline.md +5 -3
  118. package/dist/agent-src/rules/token-efficiency.md +2 -2
  119. package/dist/agent-src/rules/untrusted-input-defense.md +4 -4
  120. package/dist/agent-src/rules/user-interaction.md +12 -0
  121. package/dist/agent-src/rules/verify-before-complete.md +4 -24
  122. package/dist/agent-src/skills/adversarial-review/SKILL.md +2 -2
  123. package/dist/agent-src/skills/agent-security-review/SKILL.md +52 -45
  124. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +2 -2
  125. package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +20 -20
  126. package/dist/agent-src/skills/ai-council/SKILL.md +185 -128
  127. package/dist/agent-src/skills/analysis-skill-router/SKILL.md +3 -3
  128. package/dist/agent-src/skills/api-endpoint/SKILL.md +2 -2
  129. package/dist/agent-src/skills/artisan-commands/SKILL.md +2 -2
  130. package/dist/agent-src/skills/async-python-patterns/SKILL.md +8 -7
  131. package/dist/agent-src/skills/authz-review/SKILL.md +16 -15
  132. package/dist/agent-src/skills/aws-infrastructure/SKILL.md +5 -5
  133. package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
  134. package/dist/agent-src/skills/bug-analyzer/SKILL.md +30 -12
  135. package/dist/agent-src/skills/code-intelligence/SKILL.md +0 -1
  136. package/dist/agent-src/skills/code-intelligence/evals/triggers.json +52 -0
  137. package/dist/agent-src/skills/code-review/SKILL.md +6 -6
  138. package/dist/agent-src/skills/command-routing/SKILL.md +5 -4
  139. package/dist/agent-src/skills/composer-packages/SKILL.md +2 -2
  140. package/dist/agent-src/skills/condense-memory/SKILL.md +43 -41
  141. package/dist/agent-src/skills/context-document/SKILL.md +23 -21
  142. package/dist/agent-src/skills/copilot-config/SKILL.md +6 -1
  143. package/dist/agent-src/skills/decision-record/SKILL.md +20 -18
  144. package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
  145. package/dist/agent-src/skills/design-review/SKILL.md +15 -14
  146. package/dist/agent-src/skills/design-system-capture/reference/design-system-json.md +28 -25
  147. package/dist/agent-src/skills/devcontainer/SKILL.md +2 -2
  148. package/dist/agent-src/skills/docker/SKILL.md +1 -1
  149. package/dist/agent-src/skills/docx-authoring/evals/triggers.json +52 -0
  150. package/dist/agent-src/skills/emit-tickets/SKILL.md +2 -2
  151. package/dist/agent-src/skills/error-handling-patterns/SKILL.md +1 -1
  152. package/dist/agent-src/skills/estimate-ticket/SKILL.md +2 -2
  153. package/dist/agent-src/skills/evaluate-llm-feature/SKILL.md +0 -1
  154. package/dist/agent-src/skills/evaluate-llm-feature/evals/triggers.json +52 -0
  155. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +6 -5
  156. package/dist/agent-src/skills/feature-planning/SKILL.md +2 -2
  157. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +3 -3
  158. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  159. package/dist/agent-src/skills/frontend-render-security/SKILL.md +13 -13
  160. package/dist/agent-src/skills/git-workflow/SKILL.md +33 -33
  161. package/dist/agent-src/skills/grafana/SKILL.md +5 -0
  162. package/dist/agent-src/skills/humanizer/SKILL.md +83 -66
  163. package/dist/agent-src/skills/humanizer/data/patterns.md +14 -14
  164. package/dist/agent-src/skills/humanizer/references/anti-aiisms.md +4 -4
  165. package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +82 -37
  166. package/dist/agent-src/skills/judge-bug-hunter/SKILL.md +17 -5
  167. package/dist/agent-src/skills/judge-injection-defense/SKILL.md +63 -25
  168. package/dist/agent-src/skills/judge-security-auditor/SKILL.md +2 -0
  169. package/dist/agent-src/skills/judge-synthesis/SKILL.md +72 -28
  170. package/dist/agent-src/skills/laravel-horizon/SKILL.md +5 -0
  171. package/dist/agent-src/skills/laravel-mail/SKILL.md +5 -4
  172. package/dist/agent-src/skills/laravel-middleware/SKILL.md +5 -4
  173. package/dist/agent-src/skills/laravel-notifications/SKILL.md +10 -9
  174. package/dist/agent-src/skills/laravel-pennant/SKILL.md +1 -1
  175. package/dist/agent-src/skills/laravel-pulse/SKILL.md +9 -8
  176. package/dist/agent-src/skills/laravel-reverb/SKILL.md +6 -5
  177. package/dist/agent-src/skills/laravel-scheduling/SKILL.md +6 -1
  178. package/dist/agent-src/skills/laravel-validation/SKILL.md +12 -0
  179. package/dist/agent-src/skills/launch-readiness/SKILL.md +1 -1
  180. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +7 -7
  181. package/dist/agent-src/skills/learning-tutor/SKILL.md +44 -43
  182. package/dist/agent-src/skills/learning-tutor/evals/triggers.json +52 -0
  183. package/dist/agent-src/skills/license-compliance-audit/SKILL.md +7 -7
  184. package/dist/agent-src/skills/license-compliance-borrow-check/SKILL.md +3 -3
  185. package/dist/agent-src/skills/license-compliance-credits/SKILL.md +4 -4
  186. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +0 -1
  187. package/dist/agent-src/skills/memory-consolidation/SKILL.md +69 -64
  188. package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -6
  189. package/dist/agent-src/skills/pdf-tools/evals/triggers.json +52 -0
  190. package/dist/agent-src/skills/performance-analysis/SKILL.md +7 -3
  191. package/dist/agent-src/skills/persona-improvement/SKILL.md +0 -2
  192. package/dist/agent-src/skills/persona-improvement/evals/triggers.json +52 -0
  193. package/dist/agent-src/skills/php-coder/SKILL.md +10 -0
  194. package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +129 -120
  195. package/dist/agent-src/skills/prediction-pool-optimizer/reference/ev-fixtures.md +36 -35
  196. package/dist/agent-src/skills/prediction-pool-optimizer/reference/odds-and-bonus.md +45 -41
  197. package/dist/agent-src/skills/project-analysis-core/SKILL.md +4 -4
  198. package/dist/agent-src/skills/project-analysis-hypothesis-driven/SKILL.md +3 -3
  199. package/dist/agent-src/skills/project-analysis-react/SKILL.md +1 -1
  200. package/dist/agent-src/skills/project-analysis-symfony/SKILL.md +1 -1
  201. package/dist/agent-src/skills/project-analysis-zend-laminas/SKILL.md +2 -2
  202. package/dist/agent-src/skills/prompt-engineering-patterns/SKILL.md +1 -1
  203. package/dist/agent-src/skills/prompt-validator/SKILL.md +39 -39
  204. package/dist/agent-src/skills/quality-tools/SKILL.md +15 -15
  205. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +55 -19
  206. package/dist/agent-src/skills/react-shadcn-ui/reference/registry.md +29 -27
  207. package/dist/agent-src/skills/readme-writing-package/SKILL.md +2 -2
  208. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +25 -25
  209. package/dist/agent-src/skills/recursive-verification/SKILL.md +6 -5
  210. package/dist/agent-src/skills/refine-prompt/SKILL.md +1 -1
  211. package/dist/agent-src/skills/refine-ticket/SKILL.md +20 -2
  212. package/dist/agent-src/skills/repomix-packer/SKILL.md +1 -1
  213. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  214. package/dist/agent-src/skills/roadmap-management/SKILL.md +80 -66
  215. package/dist/agent-src/skills/roadmap-writing/SKILL.md +84 -77
  216. package/dist/agent-src/skills/rule-refactor/SKILL.md +1 -1
  217. package/dist/agent-src/skills/screenshot-hygiene/evals/triggers.json +52 -0
  218. package/dist/agent-src/skills/security-audit/SKILL.md +26 -9
  219. package/dist/agent-src/skills/security-maturity-assessment/SKILL.md +38 -16
  220. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +14 -11
  221. package/dist/agent-src/skills/skill-writing/SKILL.md +9 -8
  222. package/dist/agent-src/skills/song-to-script/SKILL.md +93 -85
  223. package/dist/agent-src/skills/sql-writing/SKILL.md +2 -2
  224. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +4 -3
  225. package/dist/agent-src/skills/standards-from-config/SKILL.md +61 -43
  226. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +22 -8
  227. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +28 -2
  228. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +13 -13
  229. package/dist/agent-src/skills/systematic-debugging/SKILL.md +22 -21
  230. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  231. package/dist/agent-src/skills/technical-specification/SKILL.md +5 -0
  232. package/dist/agent-src/skills/terraform/SKILL.md +2 -2
  233. package/dist/agent-src/skills/terragrunt/SKILL.md +8 -8
  234. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +1 -1
  235. package/dist/agent-src/skills/threat-modeling/SKILL.md +19 -13
  236. package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  237. package/dist/agent-src/skills/upstream-contribute/SKILL.md +0 -1
  238. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +9 -9
  239. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -1
  240. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +4 -6
  241. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +67 -61
  242. package/dist/agent-src/skills/video-director/SKILL.md +7 -7
  243. package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +3 -3
  244. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  245. package/dist/agent-src/templates/contexts/knowledge-pages.md +47 -45
  246. package/dist/agent-src/templates/contexts/lesson-card.md +2 -2
  247. package/dist/agent-src/templates/contexts/tenant-boundaries.md +2 -2
  248. package/dist/agent-src/templates/contexts.md +1 -1
  249. package/dist/agent-src/templates/features.md +1 -1
  250. package/dist/agent-src/templates/roadmaps.md +125 -116
  251. package/dist/agent-src/templates/rule.md +2 -1
  252. package/dist/agent-src/templates/scripts/pr_risk_review.ts +0 -0
  253. package/dist/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  254. package/dist/agent-src/templates/scripts/tier_usage_report.ts +2 -2
  255. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
  256. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
  257. package/dist/agent-src/user-types/README.md +8 -8
  258. package/dist/agent-src/user-types/galabau-field-crew.md +34 -33
  259. package/dist/agent-src/user-types/metalworking-shop.md +35 -34
  260. package/dist/agent-src/user-types/truck-driver.md +22 -20
  261. package/dist/cli/python/workspace_roles.js +2 -2
  262. package/dist/cli/python/workspace_roles.js.map +1 -1
  263. package/dist/discovery/deprecation-report.md +1 -1
  264. package/dist/discovery/discovery-manifest.json +88 -62
  265. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  266. package/dist/discovery/discovery-manifest.summary.md +3 -3
  267. package/dist/discovery/orphan-report.md +1 -1
  268. package/dist/discovery/packs.json +6 -5
  269. package/dist/discovery/trust-report.md +2 -2
  270. package/dist/discovery/workspaces.json +5 -4
  271. package/dist/hooks/dispatch.js +186 -12
  272. package/dist/install/install.mjs +8 -0
  273. package/dist/mcp/registry-manifest.json +3 -3
  274. package/dist/mcp/server.json +2 -2
  275. package/dist/mcp/server.mjs +1199 -857
  276. package/dist/router.json +1 -1
  277. package/dist/scripts/_lib/compile_time_toggles.js +48 -0
  278. package/dist/scripts/_lib/compile_time_toggles.js.map +1 -0
  279. package/dist/scripts/condense.js +234 -217
  280. package/dist/scripts/condense.js.map +1 -1
  281. package/dist/server/schemas/settings.js +4 -0
  282. package/dist/server/schemas/settings.js.map +1 -1
  283. package/dist/shared/userMd/utils.js +30 -0
  284. package/dist/shared/userMd/utils.js.map +1 -1
  285. package/dist/ui/assets/index-BpSQt5vm.js.map +1 -1
  286. package/docs/guidelines/agent-infra/api-cost-levers.md +56 -5
  287. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +93 -33
  288. package/package.json +1 -1
  289. package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
  290. package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
  291. package/src/agent-src/templates/scripts/tier_usage_report.ts +2 -2
  292. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -2
  293. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +1 -1
  294. package/src/config/agent-settings.template.yml +32 -2
  295. package/src/config/ci-local-parity.yml +142 -0
  296. package/src/config/gate-coverage.yml +127 -0
  297. package/src/config/preamble-payload-budget.json +44 -0
  298. package/src/scripts/_cli/cmd_doctor.ts +78 -2
  299. package/src/scripts/_lib/agent_user_profile.ts +381 -0
  300. package/src/scripts/_lib/agents_overlay.ts +9 -0
  301. package/src/scripts/_lib/anchor_eval.ts +311 -0
  302. package/src/scripts/_lib/cc_transcript.ts +316 -0
  303. package/src/scripts/_lib/compile_time_toggles.ts +79 -0
  304. package/src/scripts/_lib/confusables.ts +101 -0
  305. package/src/scripts/_lib/duplicate_scope_census.ts +77 -0
  306. package/src/scripts/_lib/managed_agents_folder.ts +181 -0
  307. package/src/scripts/_lib/payload_hash_drift.ts +126 -0
  308. package/src/scripts/_lib/preservation_migration.ts +291 -0
  309. package/src/scripts/_lib/retrieval_sanitize.ts +166 -2
  310. package/src/scripts/_lib/scan_scope.ts +115 -0
  311. package/src/scripts/_lib/user_global_memory_audit.ts +187 -0
  312. package/src/scripts/_lib/user_global_observations.ts +830 -0
  313. package/src/scripts/_lib/user_global_revocations.ts +110 -0
  314. package/src/scripts/_lib/user_memory_gate_counters.ts +291 -0
  315. package/src/scripts/ai_council/blind_review.ts +0 -0
  316. package/src/scripts/ai_council/budget_guard.ts +90 -11
  317. package/src/scripts/ai_council/bundler.ts +2 -2
  318. package/src/scripts/ai_council/clients.ts +59 -3
  319. package/src/scripts/ai_council/config.ts +38 -0
  320. package/src/scripts/ai_council/orchestrator.ts +54 -9
  321. package/src/scripts/ai_team/team_dispatch.ts +17 -6
  322. package/src/scripts/anchor_eval_falsify.ts +198 -0
  323. package/src/scripts/anchor_scoring_run.ts +239 -0
  324. package/src/scripts/annotate_discovery.ts +1 -65
  325. package/src/scripts/bench_quality_run.ts +168 -4
  326. package/src/scripts/cache_realization_report.ts +782 -0
  327. package/src/scripts/check_artefact_count_messaging.ts +5 -1
  328. package/src/scripts/check_augment_description_cap.ts +15 -4
  329. package/src/scripts/check_ci_local_parity.ts +317 -0
  330. package/src/scripts/check_condensation.ts +96 -191
  331. package/src/scripts/check_context_paths.ts +38 -9
  332. package/src/scripts/check_gate_coverage.ts +299 -0
  333. package/src/scripts/check_iron_law_prominence.ts +22 -1
  334. package/src/scripts/check_kernel_prefix_stability.ts +0 -0
  335. package/src/scripts/check_no_new_legacy_path.ts +16 -6
  336. package/src/scripts/check_no_roadmap_refs.ts +22 -9
  337. package/src/scripts/check_originality_freshness.ts +167 -0
  338. package/src/scripts/check_preamble_payload_budget.ts +130 -0
  339. package/src/scripts/check_proposal.ts +0 -0
  340. package/src/scripts/check_references.ts +0 -1
  341. package/src/scripts/check_safety_floor_untouched.ts +171 -24
  342. package/src/scripts/check_site_links.ts +62 -3
  343. package/src/scripts/ci_status.ts +0 -0
  344. package/src/scripts/cluster_near_miss_patterns.ts +0 -0
  345. package/src/scripts/code_graph/build.ts +0 -0
  346. package/src/scripts/command_suggester/types.ts +0 -0
  347. package/src/scripts/compile_router.ts +10 -14
  348. package/src/scripts/condense.sh +3 -4
  349. package/src/scripts/condense.ts +247 -228
  350. package/src/scripts/cost/track.mjs +168 -33
  351. package/src/scripts/cost_summary.ts +33 -1
  352. package/src/scripts/council_cli.ts +45 -3
  353. package/src/scripts/discovery_graph.ts +0 -0
  354. package/src/scripts/encoding_corpus.ts +500 -0
  355. package/src/scripts/encoding_corpus_report.ts +216 -0
  356. package/src/scripts/generate_index.ts +19 -2
  357. package/src/scripts/install-hooks.sh +2 -2
  358. package/src/scripts/learning_sidecar.ts +0 -0
  359. package/src/scripts/lint_confusables.ts +10 -72
  360. package/src/scripts/lint_featured_skills.ts +0 -0
  361. package/src/scripts/lint_hidden_unicode.ts +208 -0
  362. package/src/scripts/lint_load_context.ts +17 -5
  363. package/src/scripts/lint_new_skill_gate.ts +9 -3
  364. package/src/scripts/lint_no_python_twin_rationale.ts +17 -2
  365. package/src/scripts/lint_originality.ts +1 -1
  366. package/src/scripts/lint_skill_originality.ts +1 -1
  367. package/src/scripts/lint_ticket_buildable.ts +1 -1
  368. package/src/scripts/mcp_server/tools.ts +4 -4
  369. package/src/scripts/measure_scope_dedup.ts +224 -0
  370. package/src/scripts/memory_lookup.ts +0 -0
  371. package/src/scripts/mine_session.ts +98 -0
  372. package/src/scripts/orchestration_payload_hash_drift.ts +145 -0
  373. package/src/scripts/preamble_byte_census.ts +574 -0
  374. package/src/scripts/probe_skill_registration.ts +2 -2
  375. package/src/scripts/redact_hook_capture.ts +13 -0
  376. package/src/scripts/release.ts +65 -10
  377. package/src/scripts/router_telemetry.ts +1 -1
  378. package/src/scripts/second_brain_retrieval.ts +14 -4
  379. package/src/scripts/skill_linter.ts +5 -0
  380. package/src/scripts/surface-tiers.yml +2 -0
  381. package/src/scripts/validate_pack_yaml.ts +0 -0
  382. package/src/server/schemas/settings.ts +8 -0
  383. package/src/shared/userMd/utils.ts +31 -0
  384. package/dist/agent-src/rules/telegraph-speak.md +0 -87
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Constrained anchor evaluation with frozen verdicts (ADR-202, amended).
3
+ *
4
+ * ADR-202 originally called this "deterministic anchor-scoring against
5
+ * must_include / must_not" and claimed the scorer is "a pure function of
6
+ * (answer, anchors)". Measured against the corpus that claim is FALSE: 0 of 255
7
+ * `must_include` anchors carry a literal token or code span, and 17% are
8
+ * behavioural predicates ("mentions that UI redesign is outside scope"). A
9
+ * substring match over those measures nothing.
10
+ *
11
+ * What is deterministic is everything BELOW the verdict: aggregation, the
12
+ * per-rule floor, the non-inferiority arithmetic, κ, and the conservative
13
+ * disagreement resolution — all pure functions over frozen verdicts, all unit
14
+ * tested here without an API. The verdict itself is a constrained binary
15
+ * classification per (answer, anchor) by two independent evaluator models. That
16
+ * is far narrower than the pairwise preference judging which closed by
17
+ * diagnosis, and — the point — it restores a MEASURABLE κ, whose absence is the
18
+ * exact reason a single human judge was ruled inadmissible.
19
+ *
20
+ * Reproducibility comes from freezing, not from pinning: generate once, freeze
21
+ * the transcripts AND the verdicts as artefacts, and re-score over the frozen
22
+ * corpus. A re-generation is a new experiment, never a re-run of this one.
23
+ */
24
+
25
+ export type AnchorKind = 'must_include' | 'must_not';
26
+ export type Arm = 'thin' | 'eager';
27
+
28
+ /** One evaluator's call on one anchor. `true` = satisfied (include) / violated (not). */
29
+ export interface AnchorVerdict {
30
+ task_id: string;
31
+ arm: Arm;
32
+ kind: AnchorKind;
33
+ /** Index into the task's anchor list for that kind — stable across evaluators. */
34
+ index: number;
35
+ anchor: string;
36
+ hit: boolean;
37
+ }
38
+
39
+ /** Build the evaluator prompt for one (task, arm): every anchor in one call. */
40
+ export function eval_prompt(
41
+ prompt: string,
42
+ answer: string,
43
+ must_include: readonly string[],
44
+ must_not: readonly string[],
45
+ ): string {
46
+ const lines: string[] = [
47
+ 'You are grading ONE answer against a fixed checklist. For each checklist',
48
+ 'item, decide only whether the answer satisfies it. Judge the answer on its',
49
+ 'own — do not compare it to anything, do not reward or penalise length, and',
50
+ 'do not grade style.',
51
+ '',
52
+ '## The request the answer responds to',
53
+ '',
54
+ prompt,
55
+ '',
56
+ '## The answer',
57
+ '',
58
+ answer,
59
+ '',
60
+ '## Checklist',
61
+ '',
62
+ ];
63
+ must_include.forEach((a, i) => lines.push(`I${i}. MUST BE PRESENT: ${a}`));
64
+ must_not.forEach((a, i) => lines.push(`N${i}. MUST BE ABSENT: ${a}`));
65
+ lines.push(
66
+ '',
67
+ '## Output format — structured, one object per checklist item',
68
+ '',
69
+ 'Output a JSON array and NOTHING else. Exactly one object per checklist',
70
+ 'item, in the order listed, using the item id as `anchor_id`:',
71
+ '',
72
+ ' [{"anchor_id":"I0","verdict":"yes"},{"anchor_id":"N0","verdict":"no"}]',
73
+ '',
74
+ '`verdict` is "yes" or "no".',
75
+ ' For I items: "yes" = the answer satisfies it.',
76
+ ' For N items: "yes" = the answer DOES the forbidden thing.',
77
+ '',
78
+ `Every one of the ${must_include.length + must_not.length} items must appear. No prose, no markdown fence.`,
79
+ );
80
+ return lines.join('\n');
81
+ }
82
+
83
+ /**
84
+ * Parse an evaluator reply into verdicts. Unparseable or missing items are
85
+ * returned as `null` so the caller resolves them conservatively rather than
86
+ * silently scoring them as passes.
87
+ */
88
+ export function parse_eval(
89
+ reply: string,
90
+ must_include_len: number,
91
+ must_not_len: number,
92
+ ): { include: Array<boolean | null>; not: Array<boolean | null>; complete: boolean } {
93
+ const include: Array<boolean | null> = new Array(must_include_len).fill(null);
94
+ const not: Array<boolean | null> = new Array(must_not_len).fill(null);
95
+
96
+ const put = (tag: string, idx: number, val: boolean): void => {
97
+ if (tag === 'I') {
98
+ if (idx < include.length) include[idx] = val;
99
+ } else if (idx < not.length) not[idx] = val;
100
+ };
101
+
102
+ // Primary: structured objects. Tolerates a surrounding array, a fence, or
103
+ // one object per line — the shape matters, the packaging does not.
104
+ const obj = /\{\s*"anchor_id"\s*:\s*"([IN])(\d+)"\s*,\s*"verdict"\s*:\s*"(yes|no)"\s*\}/gi;
105
+ let m: RegExpExecArray | null;
106
+ let structured = 0;
107
+ while ((m = obj.exec(reply)) !== null) {
108
+ put(m[1]!.toUpperCase(), Number(m[2]), m[3]!.toLowerCase() === 'yes');
109
+ structured += 1;
110
+ }
111
+
112
+ // Fallback: the flat `I0=yes` form, so a model that ignores the JSON
113
+ // instruction is still read rather than silently scored as unfavourable.
114
+ if (structured === 0) {
115
+ const flat = /\b([IN])(\d+)\s*=\s*(yes|no)\b/gi;
116
+ while ((m = flat.exec(reply)) !== null) {
117
+ put(m[1]!.toUpperCase(), Number(m[2]), m[3]!.toLowerCase() === 'yes');
118
+ }
119
+ }
120
+
121
+ const complete = include.every((v) => v !== null) && not.every((v) => v !== null);
122
+ return { include, not, complete };
123
+ }
124
+
125
+ /**
126
+ * One evaluator call, with exactly one retry when the reply is incomplete or
127
+ * unparseable (attempt-2 mechanical change). A persistent failure is NOT retried
128
+ * further and NOT excluded — its `null`s flow into `resolve`, which reads them
129
+ * as the unfavourable verdict. A model that cannot answer must not be able to
130
+ * make a corpus look cleaner by staying silent.
131
+ */
132
+ export function eval_with_retry(
133
+ ask: (user: string) => string,
134
+ prompt: string,
135
+ must_include_len: number,
136
+ must_not_len: number,
137
+ ): { include: Array<boolean | null>; not: Array<boolean | null>; complete: boolean; retried: boolean } {
138
+ const first = parse_eval(ask(prompt), must_include_len, must_not_len);
139
+ if (first.complete) return { ...first, retried: false };
140
+ const second = parse_eval(ask(prompt), must_include_len, must_not_len);
141
+ return { ...second, retried: true };
142
+ }
143
+
144
+ /**
145
+ * Resolve two evaluators conservatively (ADR-202 (c)): a `must_include` counts
146
+ * only when BOTH say satisfied; a `must_not` counts as violated when EITHER says
147
+ * violated. `null` (unparsed) is treated as the unfavourable reading, so a
148
+ * malformed reply can never become a pass.
149
+ */
150
+ export function resolve(kind: AnchorKind, a: boolean | null, b: boolean | null): boolean {
151
+ if (kind === 'must_include') return a === true && b === true;
152
+ return a === true || b === true || a === null || b === null;
153
+ }
154
+
155
+ export interface TaskAnchors {
156
+ id: string;
157
+ rules: readonly string[];
158
+ must_include: readonly string[];
159
+ must_not: readonly string[];
160
+ }
161
+
162
+ export interface ScoreInput {
163
+ tasks: readonly TaskAnchors[];
164
+ /** Resolved verdicts, keyed `${task_id}|${arm}|${kind}|${index}` → hit. */
165
+ resolved: ReadonlyMap<string, boolean>;
166
+ }
167
+
168
+ export interface ArmScore {
169
+ include_pass: number;
170
+ include_total: number;
171
+ /** include_pass / include_total */
172
+ rate: number;
173
+ must_not_violations: Array<{ task_id: string; anchor: string }>;
174
+ }
175
+
176
+ export function key(task_id: string, arm: Arm, kind: AnchorKind, index: number): string {
177
+ return `${task_id}|${arm}|${kind}|${index}`;
178
+ }
179
+
180
+ export function score_arm(input: ScoreInput, arm: Arm): ArmScore {
181
+ let pass = 0;
182
+ let total = 0;
183
+ const violations: Array<{ task_id: string; anchor: string }> = [];
184
+ for (const t of input.tasks) {
185
+ t.must_include.forEach((_, i) => {
186
+ total += 1;
187
+ if (input.resolved.get(key(t.id, arm, 'must_include', i)) === true) pass += 1;
188
+ });
189
+ t.must_not.forEach((anchor, i) => {
190
+ if (input.resolved.get(key(t.id, arm, 'must_not', i)) === true) {
191
+ violations.push({ task_id: t.id, anchor });
192
+ }
193
+ });
194
+ }
195
+ return {
196
+ include_pass: pass,
197
+ include_total: total,
198
+ rate: total === 0 ? 0 : pass / total,
199
+ must_not_violations: violations,
200
+ };
201
+ }
202
+
203
+ /** Per-rule include-pass counts, for the registered floor. */
204
+ export function per_rule_passes(input: ScoreInput, arm: Arm): Map<string, number> {
205
+ const out = new Map<string, number>();
206
+ for (const t of input.tasks) {
207
+ let n = 0;
208
+ t.must_include.forEach((_, i) => {
209
+ if (input.resolved.get(key(t.id, arm, 'must_include', i)) === true) n += 1;
210
+ });
211
+ for (const r of t.rules) out.set(r, (out.get(r) ?? 0) + n);
212
+ }
213
+ return out;
214
+ }
215
+
216
+ /**
217
+ * δ proposal from the observed spread: the standard deviation of the per-task
218
+ * `must_include` pass-rate difference (thin − eager), in percentage points.
219
+ * Derived from the FROZEN corpus and recorded before scoring — a property of the
220
+ * corpus, never of the verdict.
221
+ */
222
+ export function delta_from_spread(input: ScoreInput): number {
223
+ const diffs: number[] = [];
224
+ for (const t of input.tasks) {
225
+ if (t.must_include.length === 0) continue;
226
+ let thin = 0;
227
+ let eager = 0;
228
+ t.must_include.forEach((_, i) => {
229
+ if (input.resolved.get(key(t.id, 'thin', 'must_include', i)) === true) thin += 1;
230
+ if (input.resolved.get(key(t.id, 'eager', 'must_include', i)) === true) eager += 1;
231
+ });
232
+ diffs.push((thin - eager) / t.must_include.length);
233
+ }
234
+ if (diffs.length === 0) return 0;
235
+ const mean = diffs.reduce((a, b) => a + b, 0) / diffs.length;
236
+ const varr = diffs.reduce((a, b) => a + (b - mean) ** 2, 0) / diffs.length;
237
+ return Math.sqrt(varr) * 100;
238
+ }
239
+
240
+ export interface Verdict {
241
+ kappa: number;
242
+ kappa_floor: number;
243
+ instrument_ok: boolean;
244
+ delta_pp: number;
245
+ delta_ceiling_pp: number;
246
+ delta_registered: boolean;
247
+ thin: ArmScore;
248
+ eager: ArmScore;
249
+ /** rate_thin − rate_eager, percentage points. */
250
+ rate_gap_pp: number;
251
+ must_not_ok: boolean;
252
+ non_inferiority_ok: boolean;
253
+ per_rule_floor_ok: boolean;
254
+ per_rule_floor_breaches: string[];
255
+ pass: boolean;
256
+ }
257
+
258
+ export interface VerdictOptions {
259
+ kappa: number;
260
+ kappa_floor?: number;
261
+ delta_ceiling_pp?: number;
262
+ }
263
+
264
+ /** Apply every registered threshold. Pure — the whole decision, no I/O. */
265
+ export function verdict(input: ScoreInput, opts: VerdictOptions): Verdict {
266
+ const kappa_floor = opts.kappa_floor ?? 0.8;
267
+ const delta_ceiling_pp = opts.delta_ceiling_pp ?? 3;
268
+ const thin = score_arm(input, 'thin');
269
+ const eager = score_arm(input, 'eager');
270
+ const delta_pp = delta_from_spread(input);
271
+ const delta_registered = delta_pp <= delta_ceiling_pp;
272
+ const rate_gap_pp = (thin.rate - eager.rate) * 100;
273
+
274
+ // Registered: thin introduces NO must_not violation that eager avoids.
275
+ const eagerViolated = new Set(eager.must_not_violations.map((v) => `${v.task_id}|${v.anchor}`));
276
+ const introduced = thin.must_not_violations.filter((v) => !eagerViolated.has(`${v.task_id}|${v.anchor}`));
277
+ const must_not_ok = introduced.length === 0;
278
+
279
+ const effective_delta = Math.min(delta_pp, delta_ceiling_pp);
280
+ const non_inferiority_ok = rate_gap_pp >= -effective_delta;
281
+
282
+ const thinRule = per_rule_passes(input, 'thin');
283
+ const eagerRule = per_rule_passes(input, 'eager');
284
+ const breaches: string[] = [];
285
+ for (const [rule, e] of eagerRule) {
286
+ if (e >= 1 && (thinRule.get(rule) ?? 0) === 0) breaches.push(rule);
287
+ }
288
+
289
+ const instrument_ok = opts.kappa >= kappa_floor;
290
+ return {
291
+ kappa: opts.kappa,
292
+ kappa_floor,
293
+ instrument_ok,
294
+ delta_pp,
295
+ delta_ceiling_pp,
296
+ delta_registered,
297
+ thin,
298
+ eager,
299
+ rate_gap_pp,
300
+ must_not_ok,
301
+ non_inferiority_ok,
302
+ per_rule_floor_ok: breaches.length === 0,
303
+ per_rule_floor_breaches: breaches.sort(),
304
+ pass:
305
+ instrument_ok &&
306
+ delta_registered &&
307
+ must_not_ok &&
308
+ non_inferiority_ok &&
309
+ breaches.length === 0,
310
+ };
311
+ }
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Claude Code transcript reader — replay-dedup, main/subagent classification,
3
+ * and token-usage aggregation.
4
+ *
5
+ * Metric definition (load-bearing — every consumer of this module computes
6
+ * cost/weight against this, not against `usage.input_tokens` alone):
7
+ *
8
+ * billable_input = input_tokens + cache_read_input_tokens
9
+ * + cache_creation_input_tokens
10
+ *
11
+ * Anthropic's `usage.input_tokens` field EXCLUDES cache tokens — it is only
12
+ * the uncached portion of the prompt. A cost or volume figure built from
13
+ * `input_tokens` alone silently drops the cache-read and cache-write legs.
14
+ *
15
+ * Replay dedup: Claude Code can write the same assistant turn into more than
16
+ * one transcript file (a resumed/checkpointed session re-persists prior
17
+ * turns into a new session file; a subagent's own transcript can duplicate
18
+ * turns also visible from its parent). On this repo's real
19
+ * `~/.claude/projects/` tree, 50.8% of `type: "assistant"` records with a
20
+ * `usage` block are such replays — an un-deduped sum overstates real spend
21
+ * by roughly 2x. `message.id` + `requestId` together are the closest thing
22
+ * to a stable identity for one real API call.
23
+ *
24
+ * Subagent classification: a record is a subagent leg iff its top-level
25
+ * `agentId` is present, or `isSidechain === true`. Both signals are checked
26
+ * because subagent transcripts observed under
27
+ * `<project>/<sessionId>/subagents/agent-*.jsonl` carry both, but a future
28
+ * or differently-configured transcript could carry only one.
29
+ */
30
+
31
+ import * as fs from 'node:fs';
32
+ import * as path from 'node:path';
33
+ import { homedir } from 'node:os';
34
+
35
+ /** Default base directory holding one subdirectory per Claude Code project. */
36
+ export const DEFAULT_PROJECTS_ROOT = path.join(homedir(), '.claude', 'projects');
37
+
38
+ export type TranscriptBucket = 'main' | 'subagent';
39
+
40
+ /** The six token counters every downstream metric (cost, weight, share) is built from. */
41
+ export interface TokenCounts {
42
+ input_tokens: number;
43
+ cache_read_input_tokens: number;
44
+ cache_creation_input_tokens: number;
45
+ output_tokens: number;
46
+ /** Subset of `cache_creation_input_tokens` written under the 5-minute TTL. */
47
+ ephemeral_5m_input_tokens: number;
48
+ /** Subset of `cache_creation_input_tokens` written under the 1-hour TTL. */
49
+ ephemeral_1h_input_tokens: number;
50
+ }
51
+
52
+ /** One deduped assistant turn. */
53
+ export interface TranscriptRecord {
54
+ bucket: TranscriptBucket;
55
+ agentId: string | null;
56
+ model: string;
57
+ /** Raw `timestamp` field from the record, or null when absent. */
58
+ timestamp: string | null;
59
+ usage: TokenCounts;
60
+ }
61
+
62
+ export interface ScanOptions {
63
+ /** Base directory to walk (default {@link DEFAULT_PROJECTS_ROOT}). Injectable for tests. */
64
+ root?: string;
65
+ /**
66
+ * Restrict the walk to one subdirectory of `root` — either an absolute
67
+ * path or a name relative to `root` (e.g. the encoded-cwd project dir
68
+ * `findProjectDir()` style callers already compute). Omit to scan every
69
+ * project under `root`.
70
+ */
71
+ projectDir?: string;
72
+ /** Skip `.jsonl` files whose mtime is older than this many days. */
73
+ maxAgeDays?: number;
74
+ /** Clock used to evaluate `maxAgeDays` — injectable for tests. */
75
+ now?: Date;
76
+ }
77
+
78
+ export interface ScanResult {
79
+ records: TranscriptRecord[];
80
+ /** Count of `type: "assistant"` + `usage`-bearing lines seen, before dedup. */
81
+ totalSeen: number;
82
+ /** `records.length` — the count after dedup. */
83
+ dedupedCount: number;
84
+ /** Fraction of seen records that were replays: `(totalSeen - dedupedCount) / totalSeen`. */
85
+ dedup_ratio: number;
86
+ }
87
+
88
+ /** Per-bucket rollup: call count, the four raw token sums, the TTL write split, and two derived metrics. */
89
+ export interface BucketAggregate extends TokenCounts {
90
+ bucket: TranscriptBucket;
91
+ calls: number;
92
+ /** `cache_read_input_tokens / billable_input` — 0 when billable_input is 0. */
93
+ read_share: number;
94
+ /** Cost-shaped weight: uncached input 1.0x, cache read 0.1x, 5m write 1.25x, 1h write 2.0x. */
95
+ weighted_input_units: number;
96
+ }
97
+
98
+ /** `input_tokens + cache_read_input_tokens + cache_creation_input_tokens` — see module doc comment. */
99
+ export function billableInputTokens(u: Pick<TokenCounts, 'input_tokens' | 'cache_read_input_tokens' | 'cache_creation_input_tokens'>): number {
100
+ return u.input_tokens + u.cache_read_input_tokens + u.cache_creation_input_tokens;
101
+ }
102
+
103
+ /**
104
+ * Cost-shaped weight across the four input classes. `cache_creation_input_tokens`
105
+ * that exceeds the known 5m/1h split (older records predating the TTL
106
+ * breakdown, or a partial breakdown) is treated as a 5m write — Anthropic's
107
+ * default cache TTL — rather than silently dropped.
108
+ */
109
+ export function weightedInputUnits(u: TokenCounts): number {
110
+ const knownSplit = u.ephemeral_5m_input_tokens + u.ephemeral_1h_input_tokens;
111
+ const unaccounted = Math.max(0, u.cache_creation_input_tokens - knownSplit);
112
+ return (
113
+ u.input_tokens * 1.0 +
114
+ u.cache_read_input_tokens * 0.1 +
115
+ (u.ephemeral_5m_input_tokens + unaccounted) * 1.25 +
116
+ u.ephemeral_1h_input_tokens * 2.0
117
+ );
118
+ }
119
+
120
+ function numOr0(value: unknown): number {
121
+ return typeof value === 'number' && Number.isFinite(value) ? value : 0;
122
+ }
123
+
124
+ interface RawCacheCreation {
125
+ ephemeral_5m_input_tokens?: unknown;
126
+ ephemeral_1h_input_tokens?: unknown;
127
+ }
128
+
129
+ interface RawUsage {
130
+ input_tokens?: unknown;
131
+ cache_read_input_tokens?: unknown;
132
+ cache_creation_input_tokens?: unknown;
133
+ output_tokens?: unknown;
134
+ cache_creation?: RawCacheCreation;
135
+ }
136
+
137
+ interface RawAssistantRecord {
138
+ type?: unknown;
139
+ message?: { id?: unknown; model?: unknown; usage?: RawUsage };
140
+ requestId?: unknown;
141
+ agentId?: unknown;
142
+ isSidechain?: unknown;
143
+ timestamp?: unknown;
144
+ }
145
+
146
+ function toTokenCounts(raw: RawUsage | undefined): TokenCounts {
147
+ const cc = raw?.cache_creation ?? {};
148
+ return {
149
+ input_tokens: numOr0(raw?.input_tokens),
150
+ cache_read_input_tokens: numOr0(raw?.cache_read_input_tokens),
151
+ cache_creation_input_tokens: numOr0(raw?.cache_creation_input_tokens),
152
+ output_tokens: numOr0(raw?.output_tokens),
153
+ ephemeral_5m_input_tokens: numOr0(cc.ephemeral_5m_input_tokens),
154
+ ephemeral_1h_input_tokens: numOr0(cc.ephemeral_1h_input_tokens),
155
+ };
156
+ }
157
+
158
+ /** Subagent iff a non-empty top-level `agentId` OR `isSidechain === true` — see module doc comment. */
159
+ function classifyBucket(raw: RawAssistantRecord): TranscriptBucket {
160
+ const hasAgentId = typeof raw.agentId === 'string' && raw.agentId.length > 0;
161
+ return hasAgentId || raw.isSidechain === true ? 'subagent' : 'main';
162
+ }
163
+
164
+ /** `message.id` + `requestId`, NUL-joined so no string content can forge a collision. */
165
+ function dedupKey(raw: RawAssistantRecord): string {
166
+ const id = typeof raw.message?.id === 'string' ? raw.message.id : '';
167
+ const reqId = typeof raw.requestId === 'string' ? raw.requestId : '';
168
+ return `${id}\u0000${reqId}`;
169
+ }
170
+
171
+ function parseLine(line: string): RawAssistantRecord | null {
172
+ if (line.trim().length === 0) return null;
173
+ try {
174
+ return JSON.parse(line) as RawAssistantRecord;
175
+ } catch {
176
+ return null;
177
+ }
178
+ }
179
+
180
+ /**
181
+ * List every `*.jsonl` file under `opts.root` (or `opts.root/opts.projectDir`
182
+ * when given), recursively — this is what makes `<project>/<sessionId>/
183
+ * subagents/agent-*.jsonl` visible alongside the flat `<project>/*.jsonl`
184
+ * session files without a second code path.
185
+ */
186
+ export function listTranscriptFiles(opts: ScanOptions = {}): string[] {
187
+ const root = opts.root ?? DEFAULT_PROJECTS_ROOT;
188
+ const base = opts.projectDir
189
+ ? (path.isAbsolute(opts.projectDir) ? opts.projectDir : path.join(root, opts.projectDir))
190
+ : root;
191
+ if (!fs.existsSync(base)) return [];
192
+
193
+ const cutoffMs = opts.maxAgeDays !== undefined
194
+ ? (opts.now ?? new Date()).getTime() - opts.maxAgeDays * 24 * 60 * 60 * 1000
195
+ : null;
196
+
197
+ const out: string[] = [];
198
+ const stack: string[] = [base];
199
+ while (stack.length > 0) {
200
+ const dir = stack.pop() as string;
201
+ let entries: fs.Dirent[];
202
+ try {
203
+ entries = fs.readdirSync(dir, { withFileTypes: true });
204
+ } catch {
205
+ continue;
206
+ }
207
+ for (const entry of entries) {
208
+ const full = path.join(dir, entry.name);
209
+ if (entry.isDirectory()) {
210
+ stack.push(full);
211
+ continue;
212
+ }
213
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
214
+ if (cutoffMs !== null) {
215
+ let mtimeMs: number;
216
+ try {
217
+ mtimeMs = fs.statSync(full).mtimeMs;
218
+ } catch {
219
+ continue;
220
+ }
221
+ if (mtimeMs < cutoffMs) continue;
222
+ }
223
+ out.push(full);
224
+ }
225
+ }
226
+ return out.sort();
227
+ }
228
+
229
+ /**
230
+ * Read every listed transcript file, keep only `type: "assistant"` records
231
+ * carrying a `usage` block, and dedup by {@link dedupKey}. First occurrence
232
+ * of a dedup key wins — replays carry the same usage, so occurrence order
233
+ * has no effect on the aggregated totals.
234
+ */
235
+ export function scanTranscripts(opts: ScanOptions = {}): ScanResult {
236
+ const files = listTranscriptFiles(opts);
237
+ const seen = new Set<string>();
238
+ const records: TranscriptRecord[] = [];
239
+ let totalSeen = 0;
240
+
241
+ for (const file of files) {
242
+ let text: string;
243
+ try {
244
+ text = fs.readFileSync(file, 'utf-8');
245
+ } catch {
246
+ continue;
247
+ }
248
+ for (const line of text.split('\n')) {
249
+ const raw = parseLine(line);
250
+ if (!raw || raw.type !== 'assistant' || !raw.message?.usage) continue;
251
+
252
+ totalSeen += 1;
253
+ const key = dedupKey(raw);
254
+ if (seen.has(key)) continue;
255
+ seen.add(key);
256
+
257
+ records.push({
258
+ bucket: classifyBucket(raw),
259
+ agentId: typeof raw.agentId === 'string' ? raw.agentId : null,
260
+ model: typeof raw.message.model === 'string' ? raw.message.model : 'unknown',
261
+ timestamp: typeof raw.timestamp === 'string' ? raw.timestamp : null,
262
+ usage: toTokenCounts(raw.message.usage),
263
+ });
264
+ }
265
+ }
266
+
267
+ const dedupedCount = records.length;
268
+ return {
269
+ records,
270
+ totalSeen,
271
+ dedupedCount,
272
+ dedup_ratio: totalSeen > 0 ? (totalSeen - dedupedCount) / totalSeen : 0,
273
+ };
274
+ }
275
+
276
+ function emptyAggregate(bucket: TranscriptBucket): BucketAggregate {
277
+ return {
278
+ bucket,
279
+ calls: 0,
280
+ input_tokens: 0,
281
+ cache_read_input_tokens: 0,
282
+ cache_creation_input_tokens: 0,
283
+ output_tokens: 0,
284
+ ephemeral_5m_input_tokens: 0,
285
+ ephemeral_1h_input_tokens: 0,
286
+ read_share: 0,
287
+ weighted_input_units: 0,
288
+ };
289
+ }
290
+
291
+ /** Roll deduped records up into a `main` / `subagent` pair of {@link BucketAggregate}. */
292
+ export function aggregateByBucket(records: readonly TranscriptRecord[]): Record<TranscriptBucket, BucketAggregate> {
293
+ const buckets: Record<TranscriptBucket, BucketAggregate> = {
294
+ main: emptyAggregate('main'),
295
+ subagent: emptyAggregate('subagent'),
296
+ };
297
+
298
+ for (const rec of records) {
299
+ const agg = buckets[rec.bucket];
300
+ agg.calls += 1;
301
+ agg.input_tokens += rec.usage.input_tokens;
302
+ agg.cache_read_input_tokens += rec.usage.cache_read_input_tokens;
303
+ agg.cache_creation_input_tokens += rec.usage.cache_creation_input_tokens;
304
+ agg.output_tokens += rec.usage.output_tokens;
305
+ agg.ephemeral_5m_input_tokens += rec.usage.ephemeral_5m_input_tokens;
306
+ agg.ephemeral_1h_input_tokens += rec.usage.ephemeral_1h_input_tokens;
307
+ }
308
+
309
+ for (const bucket of Object.values(buckets)) {
310
+ const billable = billableInputTokens(bucket);
311
+ bucket.read_share = billable > 0 ? bucket.cache_read_input_tokens / billable : 0;
312
+ bucket.weighted_input_units = weightedInputUnits(bucket);
313
+ }
314
+
315
+ return buckets;
316
+ }