pi-dev-team 0.2.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 (780) hide show
  1. package/LICENSE +21 -0
  2. package/PORTING.md +134 -0
  3. package/README.md +207 -0
  4. package/UPSTREAM.json +64 -0
  5. package/agents/Explore.md +15 -0
  6. package/agents/a11y-review.md +118 -0
  7. package/agents/adr-author.md +70 -0
  8. package/agents/ai-provenance-review.md +120 -0
  9. package/agents/angular-reactivity-review.md +95 -0
  10. package/agents/arch-review.md +135 -0
  11. package/agents/architect.md +78 -0
  12. package/agents/autoship-batch-proposer.md +69 -0
  13. package/agents/claude-setup-review.md +136 -0
  14. package/agents/codebase-recon.md +184 -0
  15. package/agents/component-architecture-review.md +119 -0
  16. package/agents/concurrency-review.md +109 -0
  17. package/agents/correctness-review.md +290 -0
  18. package/agents/data-flow-tracer.md +120 -0
  19. package/agents/doc-review.md +165 -0
  20. package/agents/domain-review.md +136 -0
  21. package/agents/general-purpose.md +10 -0
  22. package/agents/gherkin-quality-critic.md +113 -0
  23. package/agents/js-fp-review.md +114 -0
  24. package/agents/mutation-kill.md +684 -0
  25. package/agents/naming-review.md +142 -0
  26. package/agents/orchestrator.md +339 -0
  27. package/agents/performance-review.md +105 -0
  28. package/agents/plan-review-acceptance.md +115 -0
  29. package/agents/plan-review-design.md +90 -0
  30. package/agents/plan-review-parallelization.md +84 -0
  31. package/agents/plan-review-strategic.md +96 -0
  32. package/agents/plan-review-ux.md +110 -0
  33. package/agents/platform-engineer.md +64 -0
  34. package/agents/product-manager.md +68 -0
  35. package/agents/progress-guardian.md +79 -0
  36. package/agents/qa-engineer.md +289 -0
  37. package/agents/quality-reviewer.md +132 -0
  38. package/agents/react-reactivity-review.md +102 -0
  39. package/agents/refactor-opportunity-review.md +128 -0
  40. package/agents/security-engineer.md +60 -0
  41. package/agents/security-review.md +218 -0
  42. package/agents/session-analysis.md +95 -0
  43. package/agents/software-engineer.md +105 -0
  44. package/agents/spec-compliance-review.md +100 -0
  45. package/agents/spec-reviewer.md +114 -0
  46. package/agents/structure-review.md +146 -0
  47. package/agents/tech-writer.md +84 -0
  48. package/agents/test-review.md +246 -0
  49. package/agents/test-smell-review.md +188 -0
  50. package/agents/token-efficiency-review.md +139 -0
  51. package/agents/ui-ux-designer.md +54 -0
  52. package/agents/vue-reactivity-review.md +95 -0
  53. package/bin/__pycache__/claudecpython-314.pyc +0 -0
  54. package/bin/claude +258 -0
  55. package/docs/upstream/.pages +1 -0
  56. package/docs/upstream/CHANGELOG.md +2586 -0
  57. package/docs/upstream/README.md +155 -0
  58. package/docs/upstream/agent-architecture.md +214 -0
  59. package/docs/upstream/agent_info.md +187 -0
  60. package/docs/upstream/artifact-migration.md +124 -0
  61. package/docs/upstream/code-intelligence-nudge.md +149 -0
  62. package/docs/upstream/code-review-process.md +294 -0
  63. package/docs/upstream/concurrent-use.md +73 -0
  64. package/docs/upstream/context-management.md +111 -0
  65. package/docs/upstream/developer-notes.md +280 -0
  66. package/docs/upstream/diagrams/architecture-overview.svg +101 -0
  67. package/docs/upstream/diagrams/review-dispatch.svg +139 -0
  68. package/docs/upstream/diagrams/team-agents.svg +128 -0
  69. package/docs/upstream/diagrams/test-improve-flow.svg +166 -0
  70. package/docs/upstream/diagrams/workflow-linear.svg +66 -0
  71. package/docs/upstream/diagrams/workflow-three-phase.svg +200 -0
  72. package/docs/upstream/eval-maintenance.md +95 -0
  73. package/docs/upstream/eval-running-guide.md +147 -0
  74. package/docs/upstream/eval-system.md +291 -0
  75. package/docs/upstream/session-review-oss-complements.md +75 -0
  76. package/docs/upstream/session-review.md +212 -0
  77. package/docs/upstream/skills.md +188 -0
  78. package/docs/upstream/team-structure.md +21 -0
  79. package/docs/upstream/telemetry-ci-access.md +129 -0
  80. package/docs/upstream/telemetry-repo-security.md +120 -0
  81. package/docs/upstream/test-evaluation.md +277 -0
  82. package/docs/upstream/test-improve.md +154 -0
  83. package/docs/upstream/triage-workflow.md +282 -0
  84. package/docs/upstream/workflows.md +289 -0
  85. package/extensions/dev-team/index.ts +539 -0
  86. package/extensions/dev-team/lib/agents.ts +272 -0
  87. package/extensions/dev-team/lib/ai-credits.ts +92 -0
  88. package/extensions/dev-team/lib/autocompact.ts +81 -0
  89. package/extensions/dev-team/lib/child-run.ts +102 -0
  90. package/extensions/dev-team/lib/config.ts +236 -0
  91. package/extensions/dev-team/lib/gh-command.ts +103 -0
  92. package/extensions/dev-team/lib/github-style.ts +307 -0
  93. package/extensions/dev-team/lib/hooks.ts +350 -0
  94. package/extensions/dev-team/lib/metrics.ts +115 -0
  95. package/extensions/dev-team/lib/safe-read.ts +49 -0
  96. package/extensions/dev-team/lib/session-files.ts +57 -0
  97. package/extensions/dev-team/lib/session-spend.ts +123 -0
  98. package/extensions/dev-team/lib/shell-scan.ts +205 -0
  99. package/extensions/dev-team/lib/skills.ts +213 -0
  100. package/extensions/dev-team/lib/subagent-render.ts +245 -0
  101. package/extensions/dev-team/lib/subagent-types.ts +164 -0
  102. package/extensions/dev-team/lib/subagent.ts +596 -0
  103. package/extensions/dev-team/lib/terminal-text.ts +54 -0
  104. package/extensions/dev-team/lib/tools-misc.ts +152 -0
  105. package/extensions/dev-team/lib/transcript.ts +110 -0
  106. package/extensions/dev-team/lib/trust.ts +52 -0
  107. package/extensions/dev-team/lib/usage-breakdown.ts +176 -0
  108. package/extensions/dev-team/lib/usage-chart.ts +153 -0
  109. package/extensions/dev-team/lib/usage-command.ts +107 -0
  110. package/extensions/dev-team/lib/usage-history.ts +203 -0
  111. package/extensions/dev-team/lib/usage-render.ts +225 -0
  112. package/extensions/dev-team/lib/usage-split-bar.ts +127 -0
  113. package/extensions/dev-team/lib/usage-state.ts +116 -0
  114. package/extensions/dev-team/lib/usage-text.ts +159 -0
  115. package/extensions/dev-team/lib/usage-view.ts +109 -0
  116. package/hooks/__pycache__/refactor_test_freeze_guard.cpython-314.pyc +0 -0
  117. package/hooks/agent_dispatch_ledger.py +190 -0
  118. package/hooks/autocompact_setup_nudge.py +99 -0
  119. package/hooks/bash_retry_guard.py +228 -0
  120. package/hooks/boundary_events_write_guard.py +352 -0
  121. package/hooks/code_intelligence_nudge.py +293 -0
  122. package/hooks/code_intelligence_turn_mark.py +317 -0
  123. package/hooks/codegraph_bootstrap.py +139 -0
  124. package/hooks/contract_version_guard.py +362 -0
  125. package/hooks/cost_meter.py +106 -0
  126. package/hooks/destructive-commands.json +62 -0
  127. package/hooks/destructive_guard.py +477 -0
  128. package/hooks/eval_compliance_check.py +440 -0
  129. package/hooks/guards.json +17 -0
  130. package/hooks/hooks.json +323 -0
  131. package/hooks/internal_double_gate.py +296 -0
  132. package/hooks/js_fp_review.py +212 -0
  133. package/hooks/knowledge_index.py +119 -0
  134. package/hooks/lib/__pycache__/artifact_paths.cpython-314.pyc +0 -0
  135. package/hooks/lib/__pycache__/atomic_state.cpython-314.pyc +0 -0
  136. package/hooks/lib/__pycache__/autocompact_config.cpython-314.pyc +0 -0
  137. package/hooks/lib/__pycache__/boundary_events.cpython-314.pyc +0 -0
  138. package/hooks/lib/__pycache__/doc_classification.cpython-314.pyc +0 -0
  139. package/hooks/lib/__pycache__/gh_pr_create_detect.cpython-314.pyc +0 -0
  140. package/hooks/lib/__pycache__/git_safe_diff.cpython-314.pyc +0 -0
  141. package/hooks/lib/__pycache__/instrument_log.cpython-314.pyc +0 -0
  142. package/hooks/lib/__pycache__/metrics_query.cpython-314.pyc +0 -0
  143. package/hooks/lib/__pycache__/plugin_version.cpython-314.pyc +0 -0
  144. package/hooks/lib/__pycache__/pre_commit_doc_classifier.cpython-314.pyc +0 -0
  145. package/hooks/lib/__pycache__/review_agent_registry.cpython-314.pyc +0 -0
  146. package/hooks/lib/__pycache__/review_gate_corroboration.cpython-314.pyc +0 -0
  147. package/hooks/lib/__pycache__/review_gate_hash.cpython-314.pyc +0 -0
  148. package/hooks/lib/__pycache__/review_verdicts.cpython-314.pyc +0 -0
  149. package/hooks/lib/__pycache__/stdin_json.cpython-314.pyc +0 -0
  150. package/hooks/lib/__pycache__/stryker_invocation.cpython-314.pyc +0 -0
  151. package/hooks/lib/__pycache__/telemetry_consent.cpython-314.pyc +0 -0
  152. package/hooks/lib/__pycache__/test_file_classify.cpython-314.pyc +0 -0
  153. package/hooks/lib/__pycache__/token_efficiency_limits.cpython-314.pyc +0 -0
  154. package/hooks/lib/__pycache__/verify_guard_state.cpython-314.pyc +0 -0
  155. package/hooks/lib/__pycache__/xunit_v3_operator_gate.cpython-314.pyc +0 -0
  156. package/hooks/lib/agent_skill_hints.py +74 -0
  157. package/hooks/lib/artifact_paths.py +263 -0
  158. package/hooks/lib/atomic_state.py +557 -0
  159. package/hooks/lib/autocompact_config.py +103 -0
  160. package/hooks/lib/autoship_log.py +106 -0
  161. package/hooks/lib/banned_scripts_policy.py +51 -0
  162. package/hooks/lib/boundary_events.py +436 -0
  163. package/hooks/lib/build_knowledge_index.py +504 -0
  164. package/hooks/lib/build_skills_index.py +361 -0
  165. package/hooks/lib/build_state.py +116 -0
  166. package/hooks/lib/classify_ship_outcome.py +126 -0
  167. package/hooks/lib/config_changelog_schema.py +115 -0
  168. package/hooks/lib/cost_meter.py +955 -0
  169. package/hooks/lib/doc_classification.py +116 -0
  170. package/hooks/lib/gh_pr_create_detect.py +136 -0
  171. package/hooks/lib/git_safe_diff.py +123 -0
  172. package/hooks/lib/instrument_log.py +66 -0
  173. package/hooks/lib/iteration_journal_gate.py +197 -0
  174. package/hooks/lib/knowledge_index_paths.py +88 -0
  175. package/hooks/lib/mcp_json_repowise.py +177 -0
  176. package/hooks/lib/metrics_query.py +202 -0
  177. package/hooks/lib/minimal_yaml.py +434 -0
  178. package/hooks/lib/plugin_version.py +142 -0
  179. package/hooks/lib/pre_commit_detect.py +537 -0
  180. package/hooks/lib/pre_commit_doc_classifier.py +126 -0
  181. package/hooks/lib/pricing.py +118 -0
  182. package/hooks/lib/report_pdf.py +371 -0
  183. package/hooks/lib/review_agent_registry.py +142 -0
  184. package/hooks/lib/review_dispatch_ledger.py +101 -0
  185. package/hooks/lib/review_gate_corroboration.py +521 -0
  186. package/hooks/lib/review_gate_hash.py +252 -0
  187. package/hooks/lib/review_gate_normalized_hash.py +1115 -0
  188. package/hooks/lib/review_verdicts.py +301 -0
  189. package/hooks/lib/run_report.py +160 -0
  190. package/hooks/lib/skill_categories.yaml +125 -0
  191. package/hooks/lib/stdin_json.py +57 -0
  192. package/hooks/lib/stryker_invocation.py +102 -0
  193. package/hooks/lib/telemetry_consent.py +41 -0
  194. package/hooks/lib/telemetry_report.py +108 -0
  195. package/hooks/lib/test_file_classify.py +160 -0
  196. package/hooks/lib/token_efficiency_limits.py +51 -0
  197. package/hooks/lib/turn_identity.py +77 -0
  198. package/hooks/lib/verify_guard_state.py +110 -0
  199. package/hooks/lib/workflow_state.py +206 -0
  200. package/hooks/lib/xunit_v3_operator_gate.py +596 -0
  201. package/hooks/mcp_json_repowise_nudge.py +74 -0
  202. package/hooks/mutation_adapters/__init__.py +7 -0
  203. package/hooks/mutation_adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  204. package/hooks/mutation_adapters/__pycache__/lib.cpython-314.pyc +0 -0
  205. package/hooks/mutation_adapters/__pycache__/mutmut.cpython-314.pyc +0 -0
  206. package/hooks/mutation_adapters/__pycache__/pitest.cpython-314.pyc +0 -0
  207. package/hooks/mutation_adapters/__pycache__/stryker.cpython-314.pyc +0 -0
  208. package/hooks/mutation_adapters/__pycache__/stryker_net.cpython-314.pyc +0 -0
  209. package/hooks/mutation_adapters/lib.py +478 -0
  210. package/hooks/mutation_adapters/mutmut.py +188 -0
  211. package/hooks/mutation_adapters/pitest.py +266 -0
  212. package/hooks/mutation_adapters/stryker.py +157 -0
  213. package/hooks/mutation_adapters/stryker_net.py +264 -0
  214. package/hooks/mutation_gate.py +193 -0
  215. package/hooks/mutation_testing_smoke_gate.py +371 -0
  216. package/hooks/pending_review_notify.py +121 -0
  217. package/hooks/phase_marker.py +138 -0
  218. package/hooks/post_compact_state_reinject.py +180 -0
  219. package/hooks/post_format.py +115 -0
  220. package/hooks/pre_commit_knowledge_index.py +128 -0
  221. package/hooks/pre_commit_review.py +66 -0
  222. package/hooks/pre_pr_review.py +694 -0
  223. package/hooks/pre_tool_guard.py +405 -0
  224. package/hooks/py.sh +73 -0
  225. package/hooks/refactor-bash-write-patterns.json +29 -0
  226. package/hooks/refactor_test_bash_guard.py +253 -0
  227. package/hooks/refactor_test_freeze_guard.py +139 -0
  228. package/hooks/refactor_test_revert_guard.py +186 -0
  229. package/hooks/repo_review_nudge.py +287 -0
  230. package/hooks/review_verdict_recorder.py +464 -0
  231. package/hooks/scan_bash_command_for_banned_scripts.py +428 -0
  232. package/hooks/scan_worktree_for_banned_scripts.py +238 -0
  233. package/hooks/session_learning_trigger.py +248 -0
  234. package/hooks/skills_index.py +126 -0
  235. package/hooks/stryker_xunit_shim_guard.py +571 -0
  236. package/hooks/subagent_completion_guard.py +309 -0
  237. package/hooks/subagent_skill_context.py +139 -0
  238. package/hooks/task_completion_metrics.py +216 -0
  239. package/hooks/tdd_guard.py +229 -0
  240. package/hooks/telemetry.py +341 -0
  241. package/hooks/token_efficiency_review.py +194 -0
  242. package/hooks/verify_guard.py +183 -0
  243. package/hooks/verify_guard_edit_marker.py +73 -0
  244. package/hooks/version_check.py +173 -0
  245. package/knowledge/accepted-risks-schema.md +98 -0
  246. package/knowledge/adr-decision-criteria.md +64 -0
  247. package/knowledge/adversarial-review-protocol.md +139 -0
  248. package/knowledge/agent-registry.md +228 -0
  249. package/knowledge/agent-review-methodology.md +80 -0
  250. package/knowledge/ai-friendly-repo-guidelines.md +67 -0
  251. package/knowledge/architecture-assessment.md +96 -0
  252. package/knowledge/artifact-lifecycle.md +57 -0
  253. package/knowledge/cd-maturity-model.md +82 -0
  254. package/knowledge/cd-test-architecture.md +190 -0
  255. package/knowledge/ci-cd-file-scope.md +24 -0
  256. package/knowledge/codegraph-vs-graphify.md +192 -0
  257. package/knowledge/component-test-patterns.md +139 -0
  258. package/knowledge/database-change-management.md +80 -0
  259. package/knowledge/database-test-patterns.md +79 -0
  260. package/knowledge/decision-defaults.md +88 -0
  261. package/knowledge/dependency-breaking-techniques.md +116 -0
  262. package/knowledge/deployment-pipeline.md +86 -0
  263. package/knowledge/design-smells.md +122 -0
  264. package/knowledge/directory-enumeration.md +38 -0
  265. package/knowledge/domain-modeling.md +123 -0
  266. package/knowledge/evidence-bundle.md +90 -0
  267. package/knowledge/exploratory-testing-field-guide.md +122 -0
  268. package/knowledge/failure-routing.md +28 -0
  269. package/knowledge/fixture-construction.md +56 -0
  270. package/knowledge/frontend-component-architecture.md +139 -0
  271. package/knowledge/gherkin-quality-review-dispatch.md +135 -0
  272. package/knowledge/index.json +6766 -0
  273. package/knowledge/internal-collaborator-doubling.md +101 -0
  274. package/knowledge/legacy-test-strategy.md +71 -0
  275. package/knowledge/long-run-waiting.md +66 -0
  276. package/knowledge/microservice-testing.md +71 -0
  277. package/knowledge/model-pricing.json +23 -0
  278. package/knowledge/mutation-score-formulas.md +60 -0
  279. package/knowledge/object-calisthenics.md +147 -0
  280. package/knowledge/oracle-provenance.md +94 -0
  281. package/knowledge/orchestrator-script-implementation.md +185 -0
  282. package/knowledge/owasp-detection.md +148 -0
  283. package/knowledge/plan-review-rubric.md +56 -0
  284. package/knowledge/proxy-connectivity.md +62 -0
  285. package/knowledge/reactive-effect-patterns.md +73 -0
  286. package/knowledge/recon-inventory-excludes.txt +32 -0
  287. package/knowledge/references/bdd-value-guide.md +61 -0
  288. package/knowledge/references/csharp-http-client-testing.md +264 -0
  289. package/knowledge/release-strategies.md +74 -0
  290. package/knowledge/report-output-location.md +117 -0
  291. package/knowledge/report-pdf-integration.md +63 -0
  292. package/knowledge/report-print.css +129 -0
  293. package/knowledge/report-template.md +114 -0
  294. package/knowledge/report-to-pdf.md +69 -0
  295. package/knowledge/request-processing-flow.md +63 -0
  296. package/knowledge/result-verification.md +52 -0
  297. package/knowledge/review-agent-output-contract.md +121 -0
  298. package/knowledge/review-lens-classification.md +113 -0
  299. package/knowledge/review-rubric.md +62 -0
  300. package/knowledge/review-template.md +104 -0
  301. package/knowledge/rule-fixtures/A02.insecure-random-js/negative.js +1 -0
  302. package/knowledge/rule-fixtures/A02.insecure-random-js/positive.js +1 -0
  303. package/knowledge/rule-fixtures/A02.weak-hashing-md5/negative.py +1 -0
  304. package/knowledge/rule-fixtures/A02.weak-hashing-md5/positive.py +1 -0
  305. package/knowledge/rule-fixtures/A03.command-injection/negative.js +1 -0
  306. package/knowledge/rule-fixtures/A03.command-injection/positive.js +1 -0
  307. package/knowledge/rule-fixtures/A03.sql-injection/negative.js +1 -0
  308. package/knowledge/rule-fixtures/A03.sql-injection/positive.js +1 -0
  309. package/knowledge/rule-fixtures/A03.xss-innerhtml/negative.js +1 -0
  310. package/knowledge/rule-fixtures/A03.xss-innerhtml/positive.js +1 -0
  311. package/knowledge/rule-fixtures/A05.cors-wildcard/negative.js +1 -0
  312. package/knowledge/rule-fixtures/A05.cors-wildcard/positive.js +1 -0
  313. package/knowledge/rule-fixtures/A05.default-credentials/negative.js +1 -0
  314. package/knowledge/rule-fixtures/A05.default-credentials/positive.js +1 -0
  315. package/knowledge/rule-fixtures/A07.jwt-alg-none/negative.js +1 -0
  316. package/knowledge/rule-fixtures/A07.jwt-alg-none/positive.js +1 -0
  317. package/knowledge/rule-fixtures/A08.binary-formatter/negative.cs +1 -0
  318. package/knowledge/rule-fixtures/A08.binary-formatter/positive.cs +1 -0
  319. package/knowledge/rule-fixtures/A08.js-eval/negative.js +1 -0
  320. package/knowledge/rule-fixtures/A08.js-eval/positive.js +1 -0
  321. package/knowledge/rule-fixtures/A08.object-input-stream/negative.java +1 -0
  322. package/knowledge/rule-fixtures/A08.object-input-stream/positive.java +1 -0
  323. package/knowledge/schemas/disposition-register-v1.json +65 -0
  324. package/knowledge/schemas/recon-envelope-v1.json +198 -0
  325. package/knowledge/schemas/unified-finding-v1.json +72 -0
  326. package/knowledge/security-primitives-contract.md +301 -0
  327. package/knowledge/security-review-rule-map.yaml +107 -0
  328. package/knowledge/skills-registry.md +72 -0
  329. package/knowledge/task-size-classifier.md +103 -0
  330. package/knowledge/telemetry-schema.md +881 -0
  331. package/knowledge/test-automation-maturity.md +56 -0
  332. package/knowledge/test-automation-principles.md +71 -0
  333. package/knowledge/test-cadence-tradeoffs.md +68 -0
  334. package/knowledge/test-doubles.md +105 -0
  335. package/knowledge/test-file-indicators.md +22 -0
  336. package/knowledge/test-layer-gates.md +35 -0
  337. package/knowledge/test-matrix-examples/django-batch.md +24 -0
  338. package/knowledge/test-matrix-examples/dotnet-grpc-fronting-api.md +90 -0
  339. package/knowledge/test-matrix-examples/dotnet-http-consumer.md +131 -0
  340. package/knowledge/test-matrix-examples/react-node-spa.md +24 -0
  341. package/knowledge/test-matrix-examples/spring-boot-service.md +25 -0
  342. package/knowledge/test-matrix-examples/ssr-htmx.md +24 -0
  343. package/knowledge/test-organization.md +70 -0
  344. package/knowledge/test-pyramid.md +84 -0
  345. package/knowledge/test-refactoring.md +67 -0
  346. package/knowledge/test-review-division-of-labor.md +85 -0
  347. package/knowledge/test-smells.md +80 -0
  348. package/knowledge/test-stack-profiles/bdd-frameworks.md +235 -0
  349. package/knowledge/test-stack-profiles/django.md +13 -0
  350. package/knowledge/test-stack-profiles/dotnet.md +18 -0
  351. package/knowledge/test-stack-profiles/go.md +16 -0
  352. package/knowledge/test-stack-profiles/node.md +16 -0
  353. package/knowledge/test-stack-profiles/react.md +12 -0
  354. package/knowledge/test-stack-profiles/spring-boot.md +16 -0
  355. package/knowledge/test-stack-profiles/ssr-htmx.md +14 -0
  356. package/knowledge/test-stack-profiles/vue.md +12 -0
  357. package/knowledge/test-strategy.md +70 -0
  358. package/knowledge/testability-patterns.md +240 -0
  359. package/knowledge/testing-quadrants.md +44 -0
  360. package/knowledge/testing-techniques/approval.md +15 -0
  361. package/knowledge/testing-techniques/chaos.md +17 -0
  362. package/knowledge/testing-techniques/fuzz.md +15 -0
  363. package/knowledge/testing-techniques/property-based.md +15 -0
  364. package/knowledge/testing-techniques/schema-validation.md +15 -0
  365. package/knowledge/testing-techniques/screenshot.md +15 -0
  366. package/knowledge/three-phase-workflow.md +198 -0
  367. package/knowledge/value-patterns.md +55 -0
  368. package/knowledge/verification-mode.md +116 -0
  369. package/knowledge/virtual-service-libraries.md +75 -0
  370. package/knowledge/wave-consolidation-guidance.md +21 -0
  371. package/overrides/agents/Explore.md +15 -0
  372. package/overrides/agents/general-purpose.md +10 -0
  373. package/overrides/notes/autoship.md +6 -0
  374. package/overrides/notes/issues-from-assessment.md +3 -0
  375. package/overrides/notes/issues-from-plan.md +3 -0
  376. package/overrides/notes/mutation-night-watch.md +3 -0
  377. package/overrides/notes/mutation-testing.md +3 -0
  378. package/overrides/notes/pr.md +7 -0
  379. package/overrides/notes/project-init.md +6 -0
  380. package/overrides/notes/setup.md +13 -0
  381. package/overrides/notes/specs.md +3 -0
  382. package/overrides/skills/headless-run/SKILL.md +45 -0
  383. package/overrides/skills/upgrade/SKILL.md +30 -0
  384. package/overrides/skills/version/SKILL.md +25 -0
  385. package/package.json +36 -0
  386. package/scripts/authoring_digest.py +93 -0
  387. package/scripts/autoship_discover.py +121 -0
  388. package/scripts/autoship_group.py +409 -0
  389. package/scripts/autoship_proposals.py +494 -0
  390. package/scripts/autoship_queue.py +291 -0
  391. package/scripts/autoship_reclaim.py +495 -0
  392. package/scripts/build_jobs.py +108 -0
  393. package/scripts/build_rollback_point.py +240 -0
  394. package/scripts/build_slice_scope.py +157 -0
  395. package/scripts/build_wave.py +109 -0
  396. package/scripts/build_wave_reconcile.py +252 -0
  397. package/scripts/build_worktree_baseref.py +113 -0
  398. package/scripts/check_agent_scope.py +117 -0
  399. package/scripts/check_agent_tool_mapping.py +213 -0
  400. package/scripts/check_review_agent_mcp_tools.py +317 -0
  401. package/scripts/check_security_assessment_mcp_tools.py +165 -0
  402. package/scripts/checkpoint_abort.py +502 -0
  403. package/scripts/claude_setup_review.py +438 -0
  404. package/scripts/codebase_recon.py +556 -0
  405. package/scripts/coverage_config.py +623 -0
  406. package/scripts/coverage_delta_steering.py +330 -0
  407. package/scripts/coverage_discovery_dotnet.py +315 -0
  408. package/scripts/coverage_discovery_java.py +742 -0
  409. package/scripts/coverage_discovery_js.py +546 -0
  410. package/scripts/coverage_gap_ranking.py +556 -0
  411. package/scripts/coverage_readiness.py +455 -0
  412. package/scripts/coverage_report_parse.py +521 -0
  413. package/scripts/detect_bdd_convention.py +252 -0
  414. package/scripts/eval_ablation.py +376 -0
  415. package/scripts/gherkin_analysis_coverage_gate.py +306 -0
  416. package/scripts/gherkin_cross_feature_duplicate_titles_gate.py +173 -0
  417. package/scripts/gherkin_effectiveness_rollup.py +238 -0
  418. package/scripts/gherkin_failure_path_gate.py +206 -0
  419. package/scripts/gherkin_feature_merge.py +720 -0
  420. package/scripts/gherkin_stub_gate.py +163 -0
  421. package/scripts/gherkin_stub_merge.py +479 -0
  422. package/scripts/git_origin_host.py +88 -0
  423. package/scripts/install-java-static-analysis.py +110 -0
  424. package/scripts/issue_deps.py +74 -0
  425. package/scripts/lib/_bdd_markers.py +28 -0
  426. package/scripts/lib/_gherkin_text.py +93 -0
  427. package/scripts/lib/_vendored_tree.py +70 -0
  428. package/scripts/lib/autoship_state.py +397 -0
  429. package/scripts/lib/claude_md_guard.py +226 -0
  430. package/scripts/lib/deterministic_recon.py +446 -0
  431. package/scripts/lib/mcp_tool_grants.py +211 -0
  432. package/scripts/lib/plan_parse.py +386 -0
  433. package/scripts/lib/review_result.py +84 -0
  434. package/scripts/lib/review_roster.py +86 -0
  435. package/scripts/lib/session_log/__init__.py +34 -0
  436. package/scripts/lib/session_log/__pycache__/__init__.cpython-314.pyc +0 -0
  437. package/scripts/lib/session_log/__pycache__/records.cpython-314.pyc +0 -0
  438. package/scripts/lib/session_log/classify.py +231 -0
  439. package/scripts/lib/session_log/corrections.py +194 -0
  440. package/scripts/lib/session_log/discovery.py +108 -0
  441. package/scripts/lib/session_log/records.py +218 -0
  442. package/scripts/lib/session_log/redact.py +76 -0
  443. package/scripts/lib/session_log/signals.py +373 -0
  444. package/scripts/lib/session_report_downstream.py +614 -0
  445. package/scripts/lib/session_report_maintainer.py +1273 -0
  446. package/scripts/lib/session_report_shared.py +262 -0
  447. package/scripts/lib/settings_hook_guard.py +157 -0
  448. package/scripts/lib/slug.py +33 -0
  449. package/scripts/lib/stub_extractors/__init__.py +82 -0
  450. package/scripts/lib/stub_extractors/_common.py +328 -0
  451. package/scripts/lib/stub_extractors/csharp.py +19 -0
  452. package/scripts/lib/stub_extractors/go.py +173 -0
  453. package/scripts/lib/stub_extractors/java.py +18 -0
  454. package/scripts/lib/stub_extractors/jsts.py +126 -0
  455. package/scripts/mutation_stack_sections.py +149 -0
  456. package/scripts/mutation_yield_steering.py +345 -0
  457. package/scripts/orchestrator.py +895 -0
  458. package/scripts/plan_gherkin_export.py +227 -0
  459. package/scripts/plan_waves.py +208 -0
  460. package/scripts/pr_close_keyword_lint.py +108 -0
  461. package/scripts/progress_guardian.py +888 -0
  462. package/scripts/recon_inventory.py +273 -0
  463. package/scripts/review_findings_log.py +93 -0
  464. package/scripts/run_invariants.py +124 -0
  465. package/scripts/select_lenses.py +640 -0
  466. package/scripts/session_report.py +486 -0
  467. package/scripts/set_autocompact_env.py +221 -0
  468. package/scripts/ship_resume_guard.py +135 -0
  469. package/scripts/ship_review_gate.py +63 -0
  470. package/scripts/specs_convention_marker.py +103 -0
  471. package/scripts/test_improve_resume.py +277 -0
  472. package/scripts/test_review_mechanics.py +958 -0
  473. package/scripts/token_efficiency_review.py +322 -0
  474. package/scripts/verdict_scope.py +285 -0
  475. package/scripts/verify_gherkin_quality_critic_isolation.py +296 -0
  476. package/scripts/verify_tier.py +157 -0
  477. package/skills/adr-tools/SKILL.md +118 -0
  478. package/skills/agent-readiness/SKILL.md +105 -0
  479. package/skills/agent-readiness/ai_friendly_analyzers.py +326 -0
  480. package/skills/agent-readiness/scanner.py +441 -0
  481. package/skills/agent-readiness/scorecard.yaml +88 -0
  482. package/skills/api-design/SKILL.md +115 -0
  483. package/skills/apply-fixes/SKILL.md +171 -0
  484. package/skills/apply-test-doubles/SKILL.md +321 -0
  485. package/skills/artifact-lifecycle/SKILL.md +127 -0
  486. package/skills/autoship/SKILL.md +1124 -0
  487. package/skills/benchmark/SKILL.md +105 -0
  488. package/skills/branch-workflow/SKILL.md +89 -0
  489. package/skills/browse/SKILL.md +184 -0
  490. package/skills/browser-testing/SKILL.md +62 -0
  491. package/skills/browser-testing/references/playwright-patterns.md +216 -0
  492. package/skills/build/SKILL.md +422 -0
  493. package/skills/build/references/static-self-heal.md +245 -0
  494. package/skills/careful/SKILL.md +72 -0
  495. package/skills/cd-test-architecture/SKILL.md +371 -0
  496. package/skills/ci-debugging/SKILL.md +105 -0
  497. package/skills/co-evolution-audit/SKILL.md +269 -0
  498. package/skills/code-review/SKILL.md +1015 -0
  499. package/skills/code-review/examples/aggregated-sample.json +56 -0
  500. package/skills/code-review/examples/sample-report.md +41 -0
  501. package/skills/code-review/output-format.md +478 -0
  502. package/skills/code-review/scripts/activation.py +86 -0
  503. package/skills/code-review/scripts/change_impact.py +357 -0
  504. package/skills/code-review/scripts/change_shape.py +372 -0
  505. package/skills/code-review/scripts/change_size.py +212 -0
  506. package/skills/code-review/scripts/changed_file_list.py +141 -0
  507. package/skills/code-review/scripts/closing_pass.py +187 -0
  508. package/skills/code-review/scripts/consolidate.py +277 -0
  509. package/skills/code-review/scripts/contract_failure_report.py +185 -0
  510. package/skills/code-review/scripts/dispatch_reconcile.py +66 -0
  511. package/skills/code-review/scripts/dispatch_waves.py +164 -0
  512. package/skills/code-review/scripts/finding_signature.py +446 -0
  513. package/skills/code-review/scripts/ledger.py +283 -0
  514. package/skills/code-review/scripts/partition.py +169 -0
  515. package/skills/code-review/scripts/render_tiered_findings.py +274 -0
  516. package/skills/code-review/scripts/repo_invariants.py +1066 -0
  517. package/skills/code-review/scripts/review_context_pack.py +306 -0
  518. package/skills/code-review/scripts/review_round_log.py +345 -0
  519. package/skills/code-review/scripts/review_value_coverage.py +297 -0
  520. package/skills/code-review/scripts/validate_review_output.py +467 -0
  521. package/skills/code-review/sliced-mode.md +205 -0
  522. package/skills/competitive-analysis/SKILL.md +191 -0
  523. package/skills/context-loading-protocol/SKILL.md +157 -0
  524. package/skills/continue/SKILL.md +90 -0
  525. package/skills/cost-report/SKILL.md +178 -0
  526. package/skills/coverage-baseline/SKILL.md +335 -0
  527. package/skills/coverage-baseline/references/multi-project-discovery.md +202 -0
  528. package/skills/coverage-delta/SKILL.md +181 -0
  529. package/skills/coverage-delta/references/mutation-gate.md +70 -0
  530. package/skills/design-doc/SKILL.md +95 -0
  531. package/skills/design-interrogation/SKILL.md +89 -0
  532. package/skills/design-it-twice/SKILL.md +91 -0
  533. package/skills/docker-image-audit/SKILL.md +108 -0
  534. package/skills/docker-image-audit/references/install-guide.md +64 -0
  535. package/skills/docker-image-audit/references/report-template.md +73 -0
  536. package/skills/docker-image-create/SKILL.md +185 -0
  537. package/skills/domain-analysis/SKILL.md +183 -0
  538. package/skills/domain-driven-design/SKILL.md +194 -0
  539. package/skills/exploratory-testing/SKILL.md +108 -0
  540. package/skills/explore/SKILL.md +51 -0
  541. package/skills/farley-score/SKILL.md +165 -0
  542. package/skills/feature-file-validation/SKILL.md +78 -0
  543. package/skills/feature-file-validation/references/validation-rules.md +115 -0
  544. package/skills/feedback-learning/SKILL.md +414 -0
  545. package/skills/fix/SKILL.md +450 -0
  546. package/skills/freeze/SKILL.md +68 -0
  547. package/skills/frontend-architecture/SKILL.md +113 -0
  548. package/skills/gherkin-derive/SKILL.md +630 -0
  549. package/skills/gherkin-public/SKILL.md +266 -0
  550. package/skills/governance-compliance/SKILL.md +150 -0
  551. package/skills/guard/SKILL.md +75 -0
  552. package/skills/handoff/SKILL.md +139 -0
  553. package/skills/handoff/references/summary-templates.md +242 -0
  554. package/skills/harness-audit/SKILL.md +751 -0
  555. package/skills/harness-audit/scripts/lesson_validate.py +386 -0
  556. package/skills/harness-audit/scripts/redundancy_criterion.py +188 -0
  557. package/skills/headless-run/SKILL.md +45 -0
  558. package/skills/headless-run/scripts/isolated_dispatch.py +381 -0
  559. package/skills/help/SKILL.md +72 -0
  560. package/skills/hexagonal-architecture/SKILL.md +85 -0
  561. package/skills/human-oversight-protocol/SKILL.md +224 -0
  562. package/skills/issues-from-assessment/SKILL.md +223 -0
  563. package/skills/issues-from-plan/SKILL.md +133 -0
  564. package/skills/legacy-code/SKILL.md +132 -0
  565. package/skills/mermaid-diagramming/SKILL.md +120 -0
  566. package/skills/mutation-night-watch/SKILL.md +154 -0
  567. package/skills/mutation-night-watch/references/scheduling.md +135 -0
  568. package/skills/mutation-testing/SKILL.md +396 -0
  569. package/skills/mutation-testing/references/languages/csharp-stryker-net.md +676 -0
  570. package/skills/mutation-testing/references/languages/go-go-mutesting.md +95 -0
  571. package/skills/mutation-testing/references/languages/java-pitest.md +77 -0
  572. package/skills/mutation-testing/references/languages/javascript-stryker.md +188 -0
  573. package/skills/mutation-testing/references/languages/python-mutmut.md +97 -0
  574. package/skills/mutation-testing/references/time-estimation.md +34 -0
  575. package/skills/mutation-testing/references/tool-detection.md +15 -0
  576. package/skills/mutation-testing/references/workflow-callers.md +23 -0
  577. package/skills/mutation-testing/scripts/__pycache__/xunit_v3_feature_detector.cpython-314.pyc +0 -0
  578. package/skills/mutation-testing/scripts/csharp_stryker_net_slice_runner.py +635 -0
  579. package/skills/mutation-testing/scripts/csharp_stryker_net_status_loop.py +525 -0
  580. package/skills/mutation-testing/scripts/csharp_stryker_net_wrapper.py +681 -0
  581. package/skills/mutation-testing/scripts/mutation_baseline_reuse.py +292 -0
  582. package/skills/mutation-testing/scripts/mutation_exclude_policy.py +268 -0
  583. package/skills/mutation-testing/scripts/mutation_feasibility_gate.py +463 -0
  584. package/skills/mutation-testing/scripts/mutation_kill_headless.py +331 -0
  585. package/skills/mutation-testing/scripts/mutation_kill_insert.py +199 -0
  586. package/skills/mutation-testing/scripts/mutation_kill_insert_python.py +150 -0
  587. package/skills/mutation-testing/scripts/mutation_kill_loop.py +869 -0
  588. package/skills/mutation-testing/scripts/mutation_kill_loop_python.py +949 -0
  589. package/skills/mutation-testing/scripts/mutation_kill_retry.py +592 -0
  590. package/skills/mutation-testing/scripts/mutation_kill_shared.py +620 -0
  591. package/skills/mutation-testing/scripts/mutation_nightwatch.py +462 -0
  592. package/skills/mutation-testing/scripts/mutation_nightwatch_stacks.py +425 -0
  593. package/skills/mutation-testing/scripts/mutation_report.py +743 -0
  594. package/skills/mutation-testing/scripts/mutation_report_cli.py +175 -0
  595. package/skills/mutation-testing/scripts/mutation_safety_gate.py +69 -0
  596. package/skills/mutation-testing/scripts/stryker_shard_pipeline.py +847 -0
  597. package/skills/mutation-testing/scripts/stryker_shard_setup.py +440 -0
  598. package/skills/mutation-testing/scripts/stryker_timeout_retry.py +142 -0
  599. package/skills/mutation-testing/scripts/xunit_v3_feature_detector.py +341 -0
  600. package/skills/performance-benchmark/SKILL.md +174 -0
  601. package/skills/performance-benchmark/examples/report-format.md +43 -0
  602. package/skills/performance-benchmark/references/benchmark-script.md +169 -0
  603. package/skills/performance-metrics/SKILL.md +265 -0
  604. package/skills/plan/SKILL.md +199 -0
  605. package/skills/plan/references/gherkin-persistence.md +43 -0
  606. package/skills/plan/references/plan-template.md +182 -0
  607. package/skills/pr/SKILL.md +289 -0
  608. package/skills/pr/scripts/gate_retry_state.py +368 -0
  609. package/skills/project-init/README.md +141 -0
  610. package/skills/project-init/SKILL.md +1197 -0
  611. package/skills/project-init/evals/evals.json +200 -0
  612. package/skills/project-init/references/capability-tools.md +55 -0
  613. package/skills/project-init/references/configs.md +221 -0
  614. package/skills/property-based-testing/SKILL.md +121 -0
  615. package/skills/property-based-testing/fixtures/invariant_fixture.py +15 -0
  616. package/skills/property-based-testing/fixtures/js-roundtrip/README.md +42 -0
  617. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/LICENSE +21 -0
  618. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/README.md +263 -0
  619. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.d.ts +5165 -0
  620. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/fast-check.js +12147 -0
  621. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/package.json +3 -0
  622. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +5165 -0
  623. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.d.ts +5165 -0
  624. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/fast-check.js +12011 -0
  625. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +13 -0
  626. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/lib/types57/fast-check.d.ts +5165 -0
  627. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/fast-check/package.json +94 -0
  628. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/LICENSE +21 -0
  629. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/README.md +168 -0
  630. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +14 -0
  631. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +15 -0
  632. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformBigInt.js +38 -0
  633. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +15 -0
  634. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat32.js +18 -0
  635. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +15 -0
  636. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformFloat64.js +22 -0
  637. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +15 -0
  638. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/distribution/uniformInt.js +134 -0
  639. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +14 -0
  640. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +15 -0
  641. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +37 -0
  642. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +15 -0
  643. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +17 -0
  644. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +15 -0
  645. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +21 -0
  646. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +15 -0
  647. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +133 -0
  648. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +7 -0
  649. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/congruential32.js +44 -0
  650. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +7 -0
  651. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/mersenne.js +90 -0
  652. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +7 -0
  653. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +80 -0
  654. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +7 -0
  655. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +78 -0
  656. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/package.json +3 -0
  657. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +16 -0
  658. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
  659. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +2 -0
  660. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
  661. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +6 -0
  662. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/generateN.js +8 -0
  663. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.d.ts +12 -0
  664. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/purify.js +9 -0
  665. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +6 -0
  666. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/esm/utils/skipN.js +6 -0
  667. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.d.ts +7 -0
  668. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/congruential32.js +46 -0
  669. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.d.ts +7 -0
  670. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/mersenne.js +92 -0
  671. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +7 -0
  672. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +82 -0
  673. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +7 -0
  674. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/generator/xorshift128plus.js +80 -0
  675. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +16 -0
  676. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
  677. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +2 -0
  678. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
  679. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.d.ts +6 -0
  680. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/generateN.js +9 -0
  681. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.d.ts +12 -0
  682. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/purify.js +10 -0
  683. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.d.ts +6 -0
  684. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/lib/utils/skipN.js +7 -0
  685. package/skills/property-based-testing/fixtures/js-roundtrip/node_modules/pure-rand/package.json +133 -0
  686. package/skills/property-based-testing/fixtures/js-roundtrip/package-lock.json +1179 -0
  687. package/skills/property-based-testing/fixtures/js-roundtrip/package.json +14 -0
  688. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.js +29 -0
  689. package/skills/property-based-testing/fixtures/js-roundtrip/roundtrip.properties.test.js +16 -0
  690. package/skills/property-based-testing/fixtures/no_property_fixture.py +10 -0
  691. package/skills/property-based-testing/fixtures/roundtrip_fixture.py +16 -0
  692. package/skills/property-based-testing/references/languages/javascript.md +54 -0
  693. package/skills/property-based-testing/scripts/detect_and_dispatch.py +80 -0
  694. package/skills/property-based-testing/scripts/hypothesis_scaffold.py +276 -0
  695. package/skills/proxy-resilience/SKILL.md +84 -0
  696. package/skills/quality-gate-pipeline/SKILL.md +184 -0
  697. package/skills/quality-targets-converge/SKILL.md +254 -0
  698. package/skills/repo-review/SKILL.md +159 -0
  699. package/skills/report-pdf/SKILL.md +66 -0
  700. package/skills/review/SKILL.md +47 -0
  701. package/skills/review-agent/SKILL.md +152 -0
  702. package/skills/review-summary/SKILL.md +73 -0
  703. package/skills/run-report/SKILL.md +70 -0
  704. package/skills/semantic-duplication-scan/SKILL.md +337 -0
  705. package/skills/semantic-scan/SKILL.md +53 -0
  706. package/skills/semgrep-analyze/SKILL.md +139 -0
  707. package/skills/setup/SKILL.md +1122 -0
  708. package/skills/ship/SKILL.md +240 -0
  709. package/skills/source-verification/SKILL.md +210 -0
  710. package/skills/source-verification/scripts/claim_extractor.py +155 -0
  711. package/skills/specs/.size-baseline.json +4 -0
  712. package/skills/specs/SKILL.md +243 -0
  713. package/skills/specs/references/completeness-checklist.md +83 -0
  714. package/skills/specs/references/extraction.md +58 -0
  715. package/skills/specs/references/glossary.md +59 -0
  716. package/skills/specs/references/persistence.md +115 -0
  717. package/skills/specs/references/predictability-check.md +77 -0
  718. package/skills/static-analysis-integration/SKILL.md +235 -0
  719. package/skills/static-analysis-integration/adapters/_envelope.py +26 -0
  720. package/skills/static-analysis-integration/adapters/jscpd-adapter.py +66 -0
  721. package/skills/static-analysis-integration/adapters/lizard-adapter.py +81 -0
  722. package/skills/static-analysis-integration/adapters/mypy-adapter.py +50 -0
  723. package/skills/static-analysis-integration/adapters/mypy-src-layout.py +93 -0
  724. package/skills/static-analysis-integration/adapters/security-review-adapter.py +212 -0
  725. package/skills/static-analysis-integration/maintenance.md +23 -0
  726. package/skills/static-analysis-integration/references/language-setup.md +228 -0
  727. package/skills/static-analysis-integration/references/sarif-parser.md +124 -0
  728. package/skills/static-analysis-integration/references/security-review-adapter.md +118 -0
  729. package/skills/static-analysis-integration/references/tool-configs.md +617 -0
  730. package/skills/static-analysis-integration/rulesets/pmd-quickstart.xml +24 -0
  731. package/skills/stryker-xunit-v2-shim/SKILL.md +274 -0
  732. package/skills/stryker-xunit-v2-shim/references/shim-howto.md +256 -0
  733. package/skills/stryker-xunit-v2-shim/scripts/generate_shim.py +143 -0
  734. package/skills/systematic-debugging/SKILL.md +130 -0
  735. package/skills/telemetry/SKILL.md +75 -0
  736. package/skills/test-audit-disable/SKILL.md +129 -0
  737. package/skills/test-design/SKILL.md +177 -0
  738. package/skills/test-design/scripts/__pycache__/internal_double_detector.cpython-314.pyc +0 -0
  739. package/skills/test-design/scripts/internal_double_detector.py +631 -0
  740. package/skills/test-design-advisor/SKILL.md +166 -0
  741. package/skills/test-driven-development/SKILL.md +169 -0
  742. package/skills/test-health/SKILL.md +262 -0
  743. package/skills/test-improve/SKILL.md +239 -0
  744. package/skills/test-improve/references/phase-0-approach-contract.md +228 -0
  745. package/skills/test-improve/references/phase-1-analyze.md +131 -0
  746. package/skills/test-improve/references/phase-2-baseline.md +121 -0
  747. package/skills/test-improve/references/phase-3-derive-gherkin.md +53 -0
  748. package/skills/test-improve/references/phase-4-plan-fixes.md +34 -0
  749. package/skills/test-improve/references/phase-5-improve.md +215 -0
  750. package/skills/test-improve/references/phase-6-refactor-decision.md +45 -0
  751. package/skills/test-improve/references/phase-7-refactor.md +44 -0
  752. package/skills/test-improve/references/phase-8-validate.md +66 -0
  753. package/skills/test-improve/references/phase-9-close-out-prompt.md +11 -0
  754. package/skills/test-improve/references/phase-9-report.md +62 -0
  755. package/skills/test-improve/references/review-loop.md +92 -0
  756. package/skills/test-improve/templates/executive-summary.md +123 -0
  757. package/skills/threat-modeling/SKILL.md +108 -0
  758. package/skills/triage/SKILL.md +211 -0
  759. package/skills/ubiquitous-language/SKILL.md +192 -0
  760. package/skills/ubiquitous-language/scripts/collect_domain_signals.py +300 -0
  761. package/skills/unfreeze/SKILL.md +37 -0
  762. package/skills/upgrade/SKILL.md +31 -0
  763. package/skills/upgrade/scripts/check_version_drift.py +113 -0
  764. package/skills/upgrade/scripts/enable_autoupdate.py +149 -0
  765. package/skills/version/SKILL.md +25 -0
  766. package/sync/__pycache__/sync_upstream.cpython-314.pyc +0 -0
  767. package/sync/sync_upstream.py +293 -0
  768. package/templates/ACCEPTED-RISKS.md.tmpl +46 -0
  769. package/templates/agents/agent-template.md +151 -0
  770. package/templates/agents/angular-testing.md +66 -0
  771. package/templates/agents/csharp-quality.md +63 -0
  772. package/templates/agents/esm-enforcer.md +52 -0
  773. package/templates/agents/front-end-testing.md +65 -0
  774. package/templates/agents/go-quality.md +65 -0
  775. package/templates/agents/python-quality.md +62 -0
  776. package/templates/agents/react-testing.md +61 -0
  777. package/templates/agents/ts-enforcer.md +60 -0
  778. package/templates/agents/twelve-factor-audit.md +49 -0
  779. package/tools/entropy-check.py +250 -0
  780. package/tools/model-hash-verify.py +213 -0
@@ -0,0 +1,218 @@
1
+ """JSONL record iteration and the ``usage``-block read contract (issue
2
+ #2042, epic #2040).
3
+
4
+ Usage-block contract: today nine modules across this repo read a
5
+ transcript's ``usage`` block with four different idioms —
6
+
7
+ 1. ``usage.get(field, 0) or 0`` -> 0 on missing key AND on null
8
+ 2. ``usage.get(field) or 0`` -> 0 on missing key AND on null
9
+ 3. ``usage.get(field, 0)`` -> 0 on missing key, but a
10
+ PRESENT-and-null value
11
+ survives as `None`
12
+ 4. ``usage[field]`` -> raises `KeyError` on a
13
+ missing key
14
+
15
+ ``usage_field`` below is idiom 1/2 (they are equivalent) — the idiom already
16
+ used by BOTH extractors' own ``_accumulate_token_signals``/``_cost`` before
17
+ this package existed, so choosing it keeps golden output byte-identical
18
+ (#2042 acceptance criterion).
19
+
20
+ Why this one, not idiom 3 or 4: a real Claude Code transcript legitimately
21
+ omits a usage field two different ways. A `thinking`-only assistant message
22
+ carries no `usage` key at all (the corpus's record #2 in
23
+ `tests/fixtures/session_log/projects/.../99999999….jsonl`). A model turn
24
+ that doesn't support prompt caching has been observed to emit the field
25
+ explicitly as `usage: {"cache_creation_input_tokens": null, ...}` rather
26
+ than omitting the key (the corpus's record #3). Both cases mean the same
27
+ thing — "this field was not populated, count it as zero" — never a
28
+ legitimate non-zero value inferred from its absence. Idiom 3 would leave a
29
+ `None` sitting in an accumulator the moment a null-but-present field is hit,
30
+ raising a `TypeError` the next time arithmetic touches it (`+=`, `/ 1e6`).
31
+ Idiom 4 would abort the WHOLE extraction on the first transcript missing any
32
+ field — observed on real transcripts, not hypothetical. Idiom 1/2 is the
33
+ only one of the four that treats "missing" and "null" identically, which is
34
+ the behavior a `usage` block actually needs.
35
+ """
36
+
37
+ from __future__ import annotations
38
+
39
+ import json
40
+ from pathlib import Path
41
+
42
+ #: The four fields every extractor's token accounting reads from a usage
43
+ #: block, in the order both extractors already declared them.
44
+ USAGE_FIELDS = (
45
+ "input_tokens",
46
+ "output_tokens",
47
+ "cache_creation_input_tokens",
48
+ "cache_read_input_tokens",
49
+ )
50
+
51
+
52
+ def iter_file_records(path: Path):
53
+ """Yield every decodable JSON record in one transcript file, in order.
54
+
55
+ Streams line by line rather than `read_text().splitlines()`: transcripts
56
+ run to tens of MB and a recursive scan can visit thousands of them, where
57
+ slurping costs ~3x the file's size in peak RSS before yielding anything.
58
+ `ValueError` is caught alongside `OSError` because `UnicodeDecodeError`
59
+ is a `ValueError` — a transcript truncated mid-character by a crashed
60
+ session must not abort the whole run. `extract_session_report.py`'s
61
+ pre-#2042 copy of this function caught only `OSError`; `session_extract.py`'s
62
+ copy already had the wider catch (#1994 review) — this module keeps the
63
+ wider, safer one for both callers."""
64
+ try:
65
+ with path.open(encoding="utf-8", errors="replace") as fh:
66
+ for line in fh:
67
+ line = line.strip()
68
+ if not line:
69
+ continue
70
+ try:
71
+ yield json.loads(line)
72
+ except json.JSONDecodeError:
73
+ continue
74
+ except (OSError, ValueError):
75
+ return
76
+
77
+
78
+ def usage_of(record: dict) -> dict | None:
79
+ """Resolve one record's usage block: `message.usage` if it's a dict,
80
+ else the record's own top-level `usage` if THAT's a dict, else `None`.
81
+ Both extractors' `extract()` loops used this exact resolution order
82
+ already — moved verbatim, not changed."""
83
+ msg = record.get("message") if isinstance(record.get("message"), dict) else {}
84
+ if isinstance(msg.get("usage"), dict):
85
+ return msg["usage"]
86
+ if isinstance(record.get("usage"), dict):
87
+ return record["usage"]
88
+ return None
89
+
90
+
91
+ def usage_field(usage: dict, field: str) -> int | float:
92
+ """The one canonical reader for a single usage field. See module
93
+ docstring for the chosen null-handling contract."""
94
+ return usage.get(field, 0) or 0
95
+
96
+
97
+ def usage_fields(usage: dict) -> dict[str, int | float]:
98
+ """Every `USAGE_FIELDS` entry read through `usage_field`, in order."""
99
+ return {f: usage_field(usage, f) for f in USAGE_FIELDS}
100
+
101
+
102
+ def slim_by_name(mapping: dict) -> dict:
103
+ """Sort a name-keyed dict of Counters into a deterministic, digest-ready
104
+ shape: outer keys sorted, and each inner Counter's keys sorted too.
105
+ Shared by `session_extract.py`'s `by_model`/`by_skill` and
106
+ `extract_session_report.py`'s `by_model` — both built this exact shape
107
+ independently (the former as a dedicated `_slim` helper, the latter
108
+ inline)."""
109
+ return {k: dict(sorted(v.items())) for k, v in sorted(mapping.items())}
110
+
111
+
112
+ # --- issue #2050: sidechain/attribution primitives, made public -----------
113
+ #
114
+ # `hooks/lib/cost_meter.py`, the former context ceiling guard, and
115
+ # `scripts/measure_full_file_duplication.py` each independently read the
116
+ # harness's `isSidechain`/`attributionAgent` fields and (`cost_meter.py`/
117
+ # `measure_full_file_duplication.py`) the Task/Agent-dispatch join. Folded
118
+ # here so `skills/code-review/scripts/repo_invariants.py`'s
119
+ # `check_transcript_parsing_confined_to_session_log` (#2048) has one real
120
+ # home to point at instead of three independent copies.
121
+
122
+ #: Tool names the harness uses for subagent dispatch (both spellings appear
123
+ #: in real transcripts depending on harness version).
124
+ TASK_TOOL_NAMES = ("Task", "Agent")
125
+
126
+
127
+ def is_sidechain(record: dict) -> bool:
128
+ """True for a subagent (sidechain) transcript record — the native
129
+ top-level `isSidechain` flag, true on subagent/sidechain turns under
130
+ the older inline-record harness layout."""
131
+ return bool(record.get("isSidechain"))
132
+
133
+
134
+ def attribution_agent_of(record: dict) -> str | None:
135
+ """The record's own `attributionAgent` value when it's a string
136
+ (possibly empty), else `None`. Deliberately does not filter on
137
+ truthiness here — callers that require a non-empty value check it
138
+ themselves (`agent_type_for` below does; a caller collecting the first
139
+ attribution seen across a file, so it can prefer a later non-empty one,
140
+ does not)."""
141
+ value = record.get("attributionAgent")
142
+ return value if isinstance(value, str) else None
143
+
144
+
145
+ def join_dispatch_agent_ids(
146
+ record: dict, dispatch_types: dict[str, str], agent_types: dict[str, str]
147
+ ) -> None:
148
+ """Fold one record's subagent-dispatch metadata into the two join maps,
149
+ in place.
150
+
151
+ Two harness-recorded halves of the join (#1094):
152
+ * an assistant `tool_use` block named Task/Agent carries
153
+ `input.subagent_type` — keyed here by the block's tool-use id;
154
+ * the paired `tool_result` user record carries top-level
155
+ `toolUseResult.agentId` — completing agentId -> subagent_type.
156
+
157
+ Only the identifiers are read; prompts/descriptions are never touched.
158
+ Previously duplicated independently by `hooks/lib/cost_meter.py`'s
159
+ `_harvest_agent_dispatch` and `scripts/measure_full_file_duplication.py`'s
160
+ `_join_dispatch_agent_ids` — the latter's own docstring already conceded
161
+ the duplication "since that algorithm's own module keeps it private"
162
+ (#2050 makes it public here instead, so both consumers share one
163
+ implementation)."""
164
+ message = record.get("message")
165
+ content = message.get("content") if isinstance(message, dict) else None
166
+ if not isinstance(content, list):
167
+ return
168
+ for block in content:
169
+ if not isinstance(block, dict):
170
+ continue
171
+ block_type = block.get("type")
172
+ if block_type == "tool_use" and block.get("name") in TASK_TOOL_NAMES:
173
+ block_id = block.get("id")
174
+ block_input = block.get("input")
175
+ subagent_type = (
176
+ block_input.get("subagent_type")
177
+ if isinstance(block_input, dict)
178
+ else None
179
+ )
180
+ if (
181
+ isinstance(block_id, str)
182
+ and isinstance(subagent_type, str)
183
+ and subagent_type
184
+ ):
185
+ dispatch_types[block_id] = subagent_type
186
+ elif block_type == "tool_result":
187
+ tool_use_id = block.get("tool_use_id")
188
+ tool_use_result = record.get("toolUseResult")
189
+ agent_id = (
190
+ tool_use_result.get("agentId")
191
+ if isinstance(tool_use_result, dict)
192
+ else None
193
+ )
194
+ if (
195
+ isinstance(tool_use_id, str)
196
+ and isinstance(agent_id, str)
197
+ and tool_use_id in dispatch_types
198
+ ):
199
+ agent_types[agent_id] = dispatch_types[tool_use_id]
200
+
201
+
202
+ def agent_type_for(record: dict, agent_types: dict[str, str]) -> str:
203
+ """Agent-type bucket for one usage-bearing record (#1094).
204
+
205
+ `main` for main-loop turns. For sidechain turns: the native
206
+ `attributionAgent` field (primary), else the agentId -> subagent_type
207
+ join built from Task/Agent dispatches via `join_dispatch_agent_ids`
208
+ (fallback), else the honest `unattributed` bucket — never a guess.
209
+ """
210
+ if not is_sidechain(record):
211
+ return "main"
212
+ attribution_agent = attribution_agent_of(record)
213
+ if attribution_agent:
214
+ return attribution_agent
215
+ agent_id = record.get("agentId")
216
+ if isinstance(agent_id, str) and agent_id in agent_types:
217
+ return agent_types[agent_id]
218
+ return "unattributed"
@@ -0,0 +1,76 @@
1
+ """The privacy boundary as a function, not a convention (issue #2045, epic
2
+ #2040).
3
+
4
+ Both extractors' own docstrings promise "metrics only — no prompt text,
5
+ code, file contents, or full command strings", and
6
+ ``knowledge/telemetry-schema.md`` states the same contract. Before this
7
+ module existed, that promise was enforced only by every call site
8
+ individually remembering to run a name/path through
9
+ ``classify.safe_name``/``classify.basename`` — a convention restated at (at
10
+ last count) seventeen call sites across ``scripts/session_extract.py``,
11
+ ``plugins/dev-team/scripts/extract_session_report.py``, and
12
+ ``session_log/signals.py``. That is exactly the shape that produced this
13
+ epic (#1990/#1991/#1994: the same defect landing independently in both
14
+ forked extractors because nothing forced a shared choke point). This module
15
+ is that choke point: one function, ``redact()``, that every field value
16
+ either extractor writes to its output passes through.
17
+
18
+ ``redact()`` does not duplicate ``classify.safe_name``/``classify.basename``
19
+ — it composes them. Those two functions, and their Windows-path/allowlist
20
+ rationale, are unchanged and still individually tested; this module adds
21
+ the privacy-labeled entry point + the two-shape contract below, so a reader
22
+ (and a future call site) reaches for ``redact()`` by name rather than
23
+ re-deriving "should this be safe_name'd, basename'd, or both" from
24
+ scratch.
25
+
26
+ Real defect found while wiring this up (fixed in the same commit, not
27
+ paranoia): ``extract_session_report.py``'s ``_project_label`` used
28
+ ``os.path.basename(os.path.normpath(cwd))`` instead of the shared,
29
+ Windows-path-aware ``classify.basename`` — on a POSIX host (where this
30
+ script runs), ``os.path.basename`` splits on ``/`` only, so a Windows-
31
+ authored transcript's backslash-separated ``cwd`` came back whole. It
32
+ did not leak the raw path (``classify.safe_name``'s allowlist has no
33
+ backslash in it, so the value collapsed to ``"other"``), but every such
34
+ project's label lost its real name — this is the exact defect class the
35
+ epic's own "why this is not paranoia" note warns about (``_basename``'s
36
+ Windows-path handling is a privacy fix a hand-port already dropped once),
37
+ found a third time by routing this call site through the shared primitive
38
+ instead of a bespoke one.
39
+
40
+ Stdlib only. See ADR 0014 / ADR 0015.
41
+ """
42
+
43
+ from __future__ import annotations
44
+
45
+ from . import classify
46
+
47
+
48
+ def redact(value: str, *, from_path: bool = False) -> str:
49
+ """The one function every name/label-shaped field value passes through
50
+ before either extractor writes it to its emitted output.
51
+
52
+ - ``from_path=True``: the caller KNOWS ``value`` is a filesystem path (a
53
+ tool's ``file_path`` input, a transcript's ``cwd``) — strip to the
54
+ last path component first (``classify.basename``), then apply the
55
+ strict character allowlist (``classify.safe_name``).
56
+ - ``from_path=False`` (default): apply the strict character allowlist
57
+ directly, with NO path-stripping.
58
+
59
+ Deliberately not "always basename first, regardless of what the value
60
+ is" — a full shell command string like
61
+ ``rm -rf /tmp/SENTINEL_CMD_do_not_leak`` would basename down to
62
+ ``SENTINEL_CMD_do_not_leak`` (letters/underscores only, no slash), which
63
+ WOULD then pass the allowlist: stripping everything before the last
64
+ ``/`` can turn an unsafe string into one that only *looks* safe. The
65
+ two-shape signature keeps that failure mode impossible — a value is
66
+ only ever basenamed when the caller has affirmatively marked it as a
67
+ path.
68
+
69
+ A value that fails the allowlist collapses to ``"other"`` — never
70
+ partial content, never raised. See ``classify.safe_name``'s own
71
+ docstring for the allowlist rationale and ``classify.basename``'s for
72
+ the Windows-path history (#1991/#1994) this composes on top of,
73
+ unchanged."""
74
+ if from_path:
75
+ value = classify.basename(value)
76
+ return classify.safe_name(value)
@@ -0,0 +1,373 @@
1
+ """Per-record signal accumulation shared by both session-log extractors
2
+ (issue #2044, epic #2040) — the six drifted-furthest accumulator functions
3
+ plus one more that does the same job under a different name (`detect_
4
+ correction_turn`; the issue's own table names 7 functions while its prose
5
+ says "six", the issue is transparent about this discrepancy — the seventh is
6
+ the accuracy signal's "was this a correction turn" classifier, drifted right
7
+ alongside the other six).
8
+
9
+ Unlike session_log.discovery/records/classify (slices #2042/#2043), THIS
10
+ slice is not behavior-preserving on purpose — see the module-level and
11
+ per-function notes below for what changed, in which direction, for which
12
+ extractor, and the historical-comparability consequence. A distilled
13
+ enumeration also lives in this slice's commit body; this docstring is the
14
+ canonical, in-code record of the same decisions.
15
+
16
+ The four signal classes `/session-review`'s contract defines (docstring of
17
+ scripts/session_extract.py, mirrored in
18
+ plugins/dev-team/knowledge/telemetry-schema.md's `session-digest.jsonl`
19
+ section):
20
+
21
+ token per-session / per-skill / per-subagent / per-model token +
22
+ cost, and the cache-hit ratio.
23
+ rework failed edits, repeated file edits, retried bash, repeated
24
+ verify-loop runs, permission denials, compaction events.
25
+ accuracy tool_result is_error counts by tool, failed->retried ratio,
26
+ and user-correction turns.
27
+ utilization which skills/agents were invoked and how often, and which
28
+ registered skills/agents were never observed.
29
+
30
+ ## Per-function reconciliation
31
+
32
+ - **accumulate_token_signals** (0.10 similarity). The CORE accumulation —
33
+ sum the 4 usage fields into `tokens_total` and `by_model[model]` — is
34
+ identical in effect between the two copies; kept as the shared function,
35
+ matching `extract_session_report.py`'s existing shape exactly (no cost, no
36
+ skill). Cost computation and per-skill attribution are session_extract.py-
37
+ only EXTENSIONS layered on top by that script's own wrapper (pricing/cost
38
+ stays forked per ADR 0036) — not duplicated here.
39
+
40
+ - **The per-agent CONTEXT_TOKEN bucket (`new_agent_bucket`/
41
+ `merge_agent_buckets`/`finalize_agent_buckets`)** — not one of the 7 named
42
+ functions, but the mechanism #2029 added to `extract_session_report.py`
43
+ ONLY, giving its `by_agent_type` entries real per-agent `context_tokens`/
44
+ `context_per_dispatch` figures. `scripts/session_extract.py` had no
45
+ equivalent — its `by_agent_type` was a bare message-count `Counter`. This
46
+ slice ports the bucket machinery here and switches `session_extract.py`'s
47
+ `by_agent_type` onto it too, so **the maintainer profile gains
48
+ `context_tokens`/`context_per_dispatch`** — the deliberate, expected
49
+ output change issue #2044 calls the "clearest example of why the fork
50
+ costs something."
51
+
52
+ - **accumulate_skill_agent_signals** (0.19 similarity). session_extract.py's
53
+ copy is a strict superset: it also tracks `active` (the #711 sticky
54
+ skill/agent pointer the correction-turn signal attributes against) and
55
+ reads a legacy `attributionSkill` fallback via a `skill` parameter.
56
+ `extract_session_report.py` has neither concern (no by_skill/by_agent
57
+ correction breakdown in its report shape). The superset function is kept
58
+ as canonical; `extract_session_report.py` calls it with `skill=None` and a
59
+ throwaway `active` dict it never reads back — with `skill=None` the
60
+ legacy-fallback branch never fires, so its own `skills_invoked`/
61
+ `agent_dispatches` accumulation is unchanged (verified by golden diff
62
+ absence on that specific field).
63
+
64
+ - **track_tool_call** (0.11 similarity) and **classify_tool_result** (0.50).
65
+ Real difference: session_extract.py guards a `tool_use`/`tool_result`
66
+ block's `id`/`tool_use_id` with `isinstance(..., str)` before using it as
67
+ a dict key; extract_session_report.py's pre-#2044 copies did a bare
68
+ `.get(bid, ...)`/dict assignment, which works for any hashable `bid` but
69
+ raises `TypeError` for an unhashable one (a list or dict — a malformed or
70
+ adversarial transcript field). The safer, guarded form is kept as
71
+ canonical; extract_session_report.py gains the guard. No golden diff: the
72
+ corpus's `tool_use`/`tool_result` blocks all carry string ids.
73
+
74
+ - **track_edit** (0.58) and **track_bash** (0.42), plus the `EDIT_TOOLS`
75
+ constant both need. session_extract.py's copies keyed `verify_edited_since`/
76
+ `last_verify_norm` by `sid` inside a dict that is itself RESET at the top
77
+ of every per-file loop iteration — session-keying inside an already-
78
+ per-file-reset dict is redundant: exactly one `sessionId` ever appears in
79
+ one transcript file (the #1991 bug the sid-keying was originally built to
80
+ prevent — a review panel's siblings sharing their parent's `sessionId` and
81
+ scoring each other's retries — is already fully prevented by the per-file
82
+ reset alone, verified by `tests/repo/test_session_extract_subagents.py::
83
+ test_sibling_agents_running_one_command_are_not_retries`, which stays
84
+ green under this simplification). `extract_session_report.py`'s copies
85
+ already used the simpler flat per-thread dict
86
+ (`{"bash_commands", "last_verify_norm", "edited_since_verify"}`, built by
87
+ `new_thread()` below) with the same per-file-reset discipline. The simpler
88
+ form is kept as canonical (Simplicity First: no observable behavior
89
+ difference on any realistic transcript, confirmed by the golden harness);
90
+ `session_extract.py` drops its `sid`-keyed dicts and adopts `new_thread()`.
91
+
92
+ - **detect_correction_turn** (0.78 — closest of the seven). Logic identical
93
+ between the two copies; moved verbatim.
94
+
95
+ ## Historical `session-digest.jsonl` comparability
96
+
97
+ `by_agent_type`'s value shape changes from a bare integer (message count) to
98
+ the same bucket-dict shape `extract_session_report.py` already emitted:
99
+ `{input_tokens, cache_creation_input_tokens, cache_read_input_tokens,
100
+ output_tokens, messages, dispatches, context_tokens, context_per_dispatch}`.
101
+ Any historical `session-digest.jsonl` row is NOT comparable on
102
+ `token.by_agent_type` (and the derived `session-sync` `by_thread` field)
103
+ against a row produced after this change — a consumer doing
104
+ `by_agent_type[x] == N` or arithmetic on the value breaks. This is the same
105
+ shape of jump `session-digest/v2` (#1994) already made once. The formal
106
+ schema-version bump (`session-digest/v3`) and any migration/split-on-schema
107
+ consumer update is explicitly issue #2045's job, not this slice's — this
108
+ slice only flags it, per its own acceptance criteria.
109
+ """
110
+
111
+ from __future__ import annotations
112
+
113
+ import re
114
+ from collections import Counter
115
+
116
+ from session_log import classify, redact
117
+
118
+ #: Tools whose `tool_use` counts as an "edit" for rework tracking. Not one
119
+ #: of ADR 0036's 14 classify.py symbols, but tightly coupled to the edit/
120
+ #: bash signal functions below, so it lives here rather than in classify.py.
121
+ EDIT_TOOLS = {"Edit", "Write", "NotebookEdit", "MultiEdit"}
122
+
123
+ #: The usage fields that make up a dispatch's CONTEXT — what it carried in,
124
+ #: as opposed to what it generated. Session telemetry puts ~90% of spend
125
+ #: here (cache read + cache write), which is why per-agent context is the
126
+ #: figure a panel-cost decision needs and `output_tokens` is tracked
127
+ #: separately. Ported verbatim from extract_session_report.py (#2029).
128
+ CONTEXT_TOKEN_FIELDS = (
129
+ "input_tokens",
130
+ "cache_creation_input_tokens",
131
+ "cache_read_input_tokens",
132
+ )
133
+
134
+ #: Mirrors `hooks/lib/cost_meter.py`'s `_new_bucket()` shape (#1094) so the
135
+ #: per-agent breakdowns agree on field names across the plugin. They stay
136
+ #: separate implementations — cost_meter runs live per turn, this runs over
137
+ #: a whole transcript tree.
138
+ AGENT_BUCKET_FIELDS = (*CONTEXT_TOKEN_FIELDS, "output_tokens")
139
+
140
+
141
+ def new_agent_bucket() -> dict:
142
+ bucket = {f: 0 for f in AGENT_BUCKET_FIELDS}
143
+ bucket["messages"] = 0
144
+ bucket["dispatches"] = 0
145
+ return bucket
146
+
147
+
148
+ def merge_agent_buckets(dest: dict, src: dict) -> None:
149
+ """Fold one project's per-agent buckets into cross-project totals.
150
+
151
+ Re-sums the raw fields rather than the derived ones: adding two
152
+ projects' `context_per_dispatch` values would produce a number that is
153
+ not a mean of anything. The derived figures are recomputed once, after
154
+ the merge."""
155
+ for label, bucket in (src or {}).items():
156
+ if not isinstance(bucket, dict):
157
+ # A digest written before this port (or before #2010 downstream)
158
+ # carries an int (a message count). Merging it as tokens would
159
+ # silently corrupt the total, so the label is preserved at zero
160
+ # rather than guessed at.
161
+ dest.setdefault(label, new_agent_bucket())
162
+ continue
163
+ into = dest.setdefault(label, new_agent_bucket())
164
+ for field in (*AGENT_BUCKET_FIELDS, "messages", "dispatches"):
165
+ into[field] += bucket.get(field, 0) or 0
166
+
167
+
168
+ def finalize_agent_buckets(by_agent_type: dict) -> dict:
169
+ """Add the derived per-dispatch figure each bucket exists to answer.
170
+
171
+ `context_tokens` is the sum a dispatch is charged for carrying;
172
+ `context_per_dispatch` divides it by real dispatch count, which is why
173
+ dispatches are counted from subagent transcripts rather than messages.
174
+ It is `None` for `main` and for any agent with no counted dispatch — a
175
+ division that has no meaning must read as absent, not as 0, which would
176
+ rank a never-dispatched agent as the cheapest in the table."""
177
+ out = {}
178
+ for label, b in sorted(by_agent_type.items()):
179
+ context = sum(b[f] for f in CONTEXT_TOKEN_FIELDS)
180
+ entry = dict(b)
181
+ entry["context_tokens"] = context
182
+ entry["context_per_dispatch"] = (
183
+ round(context / b["dispatches"]) if b["dispatches"] else None
184
+ )
185
+ out[label] = entry
186
+ return out
187
+
188
+
189
+ def accumulate_token_signals(usage_fields: dict, model, tokens_total, by_model) -> None:
190
+ """Token-accounting CORE: sum `usage_fields` (already read through
191
+ `session_log.records.usage_fields`) into `tokens_total` and
192
+ `by_model[model]`. No cost, no skill attribution — those stay
193
+ session_extract.py-only extensions (pricing/cost stays forked, ADR
194
+ 0036); see this module's docstring."""
195
+ for f, v in usage_fields.items():
196
+ tokens_total[f] += v
197
+ if model:
198
+ by_model[model][f] += v
199
+
200
+
201
+ def accumulate_skill_agent_signals(
202
+ skill,
203
+ content,
204
+ skills_invoked: Counter,
205
+ agent_dispatches: Counter,
206
+ active: dict[str, str | tuple[str, str] | None],
207
+ ) -> None:
208
+ """Skill/agent-detection concern. `skill` is the legacy attributionSkill
209
+ tag (kept as a fallback — real transcripts don't emit it, #182);
210
+ `content`'s tool_use blocks are the primary signal: the Skill tool and
211
+ the Agent/Task tool that actually invoke them (#182). `active` tracks
212
+ the most-recently-invoked skill/agent (#711), sticky until superseded,
213
+ for the correction-turn concern to attribute against. `active["last"]`
214
+ (#2013) is the same pointer collapsed to a single `(kind, name)` tuple
215
+ (or absent, before any dispatch) -- the ONE most-recently-dispatched
216
+ entity between the two, for `session_log.corrections`' `component`
217
+ field, which needs a single answer rather than two independently-sticky
218
+ ones.
219
+
220
+ Counts DISPATCHES, not runs: a dispatch made from inside a subagent is
221
+ only visible in that subagent's own transcript, and a dispatch whose
222
+ transcript is absent never ran. Run counts come from `attributionAgent`
223
+ (#1994)."""
224
+ if skill:
225
+ skills_invoked[redact.redact(skill)] += 1
226
+ if not isinstance(content, list):
227
+ return
228
+ for block in content:
229
+ if not isinstance(block, dict) or block.get("type") != "tool_use":
230
+ continue
231
+ name = block.get("name", "?")
232
+ inp = block.get("input", {}) if isinstance(block.get("input"), dict) else {}
233
+ if name == "Skill":
234
+ s = inp.get("skill") or inp.get("name")
235
+ if isinstance(s, str) and s:
236
+ active["skill"] = redact.redact(classify.strip_ns(s))
237
+ skills_invoked[active["skill"]] += 1
238
+ active["last"] = ("skill", active["skill"])
239
+ elif name in ("Agent", "Task"):
240
+ a = inp.get("subagent_type")
241
+ if isinstance(a, str) and a:
242
+ active["agent"] = redact.redact(classify.strip_ns(a))
243
+ agent_dispatches[active["agent"]] += 1
244
+ active["last"] = ("agent", active["agent"])
245
+
246
+
247
+ def track_tool_call(block: dict, pending_tool: dict[str, str], tool_calls: Counter) -> None:
248
+ """Error-classification bookkeeping: count every tool invocation (the
249
+ error-rate denominator) and remember its id -> name so a later
250
+ tool_result can be attributed back to the tool that produced it."""
251
+ name = redact.redact(str(block.get("name", "?")))
252
+ tool_calls[name] += 1
253
+ bid = block.get("id")
254
+ if isinstance(bid, str) and bid:
255
+ pending_tool[bid] = name
256
+
257
+
258
+ def classify_tool_result(
259
+ block: dict,
260
+ pending_tool: dict[str, str],
261
+ tool_errors: Counter,
262
+ error_counts: Counter,
263
+ ) -> None:
264
+ """Error-classification concern: tally errors by tool, and detect the
265
+ two rework sub-signals (failed edits via old_string mismatches, and
266
+ permission denials) from a tool_result block."""
267
+ if not block.get("is_error"):
268
+ return
269
+ bid = block.get("tool_use_id")
270
+ tool_name = pending_tool.get(bid, "?") if isinstance(bid, str) else "?"
271
+ tool_errors[tool_name] += 1
272
+ rcontent = classify.text_of(block.get("content"))
273
+ if tool_name in EDIT_TOOLS and classify.OLDSTRING_RE.search(rcontent):
274
+ error_counts["failed_edits"] += 1
275
+ if classify.PERMISSION_RE.search(rcontent):
276
+ error_counts["permission_denials"] += 1
277
+
278
+
279
+ def new_thread() -> dict:
280
+ """Per-transcript-file state for `track_edit`/`track_bash`. One
281
+ transcript file is one thread of execution: a main-thread session, or a
282
+ single dispatched agent's run. Reset at the top of each file's
283
+ processing loop."""
284
+ return {"bash_commands": Counter(), "last_verify_norm": None, "edited_since_verify": False}
285
+
286
+
287
+ def track_edit(block: dict, edits_per_file: Counter, thread: dict) -> None:
288
+ """Edit-tracking concern: count Edit/Write/... calls per file basename,
289
+ so repeated edits to the same file (a rework signal) can be derived.
290
+ Also marks this thread's pending stuck-verify-loop streak (#708) as
291
+ consumed — an edit resets it, same as verify_guard.py's own reset."""
292
+ name = block.get("name", "?")
293
+ inp = block.get("input", {}) if isinstance(block.get("input"), dict) else {}
294
+ if name in EDIT_TOOLS and inp.get("file_path"):
295
+ edits_per_file[redact.redact(str(inp["file_path"]), from_path=True)] += 1
296
+ if name in EDIT_TOOLS:
297
+ thread["edited_since_verify"] = True
298
+
299
+
300
+ def track_bash(
301
+ block: dict,
302
+ bash_signal_counts: Counter,
303
+ thread: dict,
304
+ *,
305
+ active: dict | None = None,
306
+ retried_by_skill: Counter | None = None,
307
+ retried_by_agent: Counter | None = None,
308
+ ) -> None:
309
+ """Bash-retry / commit-bypass / stuck-verify-loop concern (#111, #708):
310
+ normalize the command for near-identical retry detection, detect a
311
+ stuck-verify-loop repeat (the same normalized verify command run again
312
+ with no Edit/Write/... call since the previous run in this thread), and
313
+ detect the review-gate bypass signal on `git commit` invocations.
314
+
315
+ Bash signals are scoped to ONE thread of execution (`thread`, a
316
+ per-transcript-file dict). Retries and repeated verify runs are only
317
+ meaningful within a thread: a review panel's sibling agents share their
318
+ parent's sessionId, so a session-keyed tally would score fifteen agents
319
+ each running `git diff --cached` once as fourteen retries.
320
+
321
+ `active`/`retried_by_skill`/`retried_by_agent` (#2110) attribute each
322
+ retry, at the moment it's detected, to whichever skill/agent is the
323
+ thread's current sticky pointer (`active["skill"]`/`active["agent"]`,
324
+ the same pointer `accumulate_skill_agent_signals` maintains and the
325
+ correction-turn signal already attributes against) — "unattributed"
326
+ when neither is set. All three are optional and default to no
327
+ attribution, so a caller with no `active` pointer to offer (there is
328
+ none today) gets the prior behavior unchanged."""
329
+ name = block.get("name", "?")
330
+ inp = block.get("input", {}) if isinstance(block.get("input"), dict) else {}
331
+ if name != "Bash" or not isinstance(inp.get("command"), str):
332
+ return
333
+ cmd = inp["command"].strip()
334
+ # near-identical retry detection: normalize whitespace
335
+ norm = re.sub(r"\s+", " ", cmd)
336
+ if active is not None and thread["bash_commands"][norm] >= 1:
337
+ # This exact normalized command already ran once in this thread —
338
+ # this call is a retry, attributed to whichever skill/agent is
339
+ # active right now.
340
+ if retried_by_skill is not None:
341
+ retried_by_skill[active.get("skill") or "unattributed"] += 1
342
+ if retried_by_agent is not None:
343
+ retried_by_agent[active.get("agent") or "unattributed"] += 1
344
+ thread["bash_commands"][norm] += 1
345
+ if classify.VERIFY_RE.search(cmd):
346
+ if thread["last_verify_norm"] == norm and not thread["edited_since_verify"]:
347
+ bash_signal_counts["repeated_verify_runs"] += 1
348
+ thread["last_verify_norm"] = norm
349
+ thread["edited_since_verify"] = False
350
+ # gate signal (#111): commit + review-gate bypass, scoped to the
351
+ # git-commit argv (#2036) — see classify.bash_segments()/is_git_commit_argv().
352
+ for segment in classify.bash_segments(cmd):
353
+ if classify.is_git_commit_argv(segment):
354
+ bash_signal_counts["commit_attempts"] += 1
355
+ if any(tok in classify.COMMIT_BYPASS_TOKENS for tok in segment[1:]):
356
+ bash_signal_counts["commit_bypasses"] += 1
357
+
358
+
359
+ def detect_correction_turn(rec: dict, content) -> bool:
360
+ """Correction-turn concern: a real user message (not a tool_result
361
+ envelope) containing a correction keyword ("no", "actually", "revert",
362
+ ...)."""
363
+ if rec.get("type") != "user" or rec.get("isMeta"):
364
+ return False
365
+ utext = classify.text_of(content)
366
+ if not utext:
367
+ return False
368
+ # skip pure tool_result envelopes (no free-text user prompt)
369
+ if isinstance(content, list) and all(
370
+ isinstance(b, dict) and b.get("type") == "tool_result" for b in content
371
+ ):
372
+ return False
373
+ return bool(classify.CORRECTION_RE.search(utext.lower()))