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,152 @@
1
+ /**
2
+ * Small tools the dev-team content expects from Claude Code:
3
+ * ask_user — AskUserQuestion (human gates in /plan, /specs, /build, /setup, ...)
4
+ * web_fetch — WebFetch (source-verification, competitive-analysis)
5
+ */
6
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
7
+ import { Type } from "typebox";
8
+
9
+ const OptionSchema = Type.Object({
10
+ label: Type.String(),
11
+ description: Type.Optional(Type.String()),
12
+ });
13
+
14
+ const QuestionSchema = Type.Object({
15
+ question: Type.String({ description: "The question to ask" }),
16
+ header: Type.Optional(Type.String({ description: "Short label" })),
17
+ options: Type.Optional(Type.Array(OptionSchema, { description: "Choices; omit for a free-text answer" })),
18
+ multiSelect: Type.Optional(Type.Boolean()),
19
+ });
20
+
21
+ const AskParams = Type.Object({
22
+ question: Type.Optional(Type.String({ description: "Single question (or use `questions`)" })),
23
+ options: Type.Optional(Type.Array(Type.Union([Type.String(), OptionSchema]))),
24
+ multiSelect: Type.Optional(Type.Boolean()),
25
+ questions: Type.Optional(Type.Array(QuestionSchema, { description: "Several questions (Claude AskUserQuestion shape)" })),
26
+ });
27
+
28
+ type Q = { question: string; header?: string; options?: { label: string; description?: string }[]; multiSelect?: boolean };
29
+
30
+ const OTHER = "Other (type an answer)";
31
+
32
+ async function askOne(q: Q, ctx: ExtensionContext): Promise<string | undefined> {
33
+ const title = q.header ? `${q.header}: ${q.question}` : q.question;
34
+ if (!q.options?.length) return ctx.ui.input(title);
35
+ const labels = q.options.map((o) => (o.description ? `${o.label} — ${o.description}` : o.label));
36
+ if (q.multiSelect) {
37
+ const listing = labels.map((l, i) => `${i + 1}. ${l}`).join("\n");
38
+ const raw = await ctx.ui.input(`${title}\n${listing}\nEnter numbers separated by commas, or free text`);
39
+ if (raw === undefined) return undefined;
40
+ const picks = raw
41
+ .split(",")
42
+ .map((s) => Number(s.trim()))
43
+ .filter((n) => Number.isInteger(n) && n >= 1 && n <= labels.length);
44
+ return picks.length ? picks.map((n) => q.options?.[n - 1]?.label).join(", ") : raw;
45
+ }
46
+ const choice = await ctx.ui.select(title, [...labels, OTHER]);
47
+ if (choice === undefined) return undefined;
48
+ if (choice === OTHER) return ctx.ui.input(title);
49
+ return q.options[labels.indexOf(choice)]?.label ?? choice;
50
+ }
51
+
52
+ export function registerAskUser(pi: ExtensionAPI): void {
53
+ pi.registerTool({
54
+ name: "ask_user",
55
+ label: "Ask user",
56
+ description:
57
+ "Ask the human one or more questions (Claude Code's AskUserQuestion). Use for dev-team human gates: approvals, ambiguity resolution, choices. In non-interactive runs it returns that no human is attached; then take the documented non-interactive default.",
58
+ promptSnippet: "Ask the human a question (AskUserQuestion equivalent)",
59
+ parameters: AskParams,
60
+ executionMode: "sequential",
61
+ // It asks the human, so only the model may call it, never a codemode script.
62
+ exposure: "model-only",
63
+ annotations: { readOnlyHint: true, openWorldHint: false },
64
+ async execute(_id, params, _signal, _onUpdate, ctx) {
65
+ const questions: Q[] = params.questions?.length
66
+ ? (params.questions as Q[])
67
+ : params.question
68
+ ? [
69
+ {
70
+ question: params.question,
71
+ options: params.options?.map((o) => (typeof o === "string" ? { label: o } : o)),
72
+ multiSelect: params.multiSelect,
73
+ },
74
+ ]
75
+ : [];
76
+ if (!questions.length) throw new Error("Provide `question` or `questions`.");
77
+ if (!ctx.hasUI || process.env.DEV_TEAM_INTERACTIVE !== "1") {
78
+ return {
79
+ content: [
80
+ {
81
+ type: "text",
82
+ text: "NON-INTERACTIVE: no human is attached to this run. Do not wait. Apply the documented non-interactive default for this gate and record that you did.",
83
+ },
84
+ ],
85
+ details: { answered: false },
86
+ };
87
+ }
88
+ const answers: { question: string; answer: string | null }[] = [];
89
+ for (const q of questions) {
90
+ const a = await askOne(q, ctx);
91
+ answers.push({ question: q.question, answer: a ?? null });
92
+ }
93
+ const text = answers.map((a) => `Q: ${a.question}\nA: ${a.answer ?? "(dismissed — no answer)"}`).join("\n\n");
94
+ return { content: [{ type: "text", text }], details: { answered: true, answers } };
95
+ },
96
+ });
97
+ }
98
+
99
+ function htmlToText(html: string): string {
100
+ return html
101
+ .replace(/<script[\s\S]*?<\/script>/gi, "")
102
+ .replace(/<style[\s\S]*?<\/style>/gi, "")
103
+ .replace(/<noscript[\s\S]*?<\/noscript>/gi, "")
104
+ .replace(/<(br|\/p|\/div|\/li|\/h[1-6]|\/tr)>/gi, "\n")
105
+ .replace(/<li[^>]*>/gi, "- ")
106
+ .replace(/<[^>]+>/g, "")
107
+ .replace(/&nbsp;/g, " ")
108
+ .replace(/&amp;/g, "&")
109
+ .replace(/&lt;/g, "<")
110
+ .replace(/&gt;/g, ">")
111
+ .replace(/&quot;/g, '"')
112
+ .replace(/&#39;/g, "'")
113
+ .replace(/[ \t]+/g, " ")
114
+ .replace(/\n\s*\n\s*\n+/g, "\n\n")
115
+ .trim();
116
+ }
117
+
118
+ const FETCH_CAP = 60_000;
119
+
120
+ export function registerWebFetch(pi: ExtensionAPI): void {
121
+ pi.registerTool({
122
+ name: "web_fetch",
123
+ label: "Web fetch",
124
+ description:
125
+ "Fetch a URL and return its text (Claude Code's WebFetch). HTML is converted to plain text; output is capped. `prompt` states what you are looking for; extract it yourself from the returned text.",
126
+ promptSnippet: "Fetch a web page as text (WebFetch equivalent)",
127
+ parameters: Type.Object({
128
+ url: Type.String({ description: "http(s) URL" }),
129
+ prompt: Type.Optional(Type.String({ description: "What to look for in the page" })),
130
+ }),
131
+ annotations: { readOnlyHint: true, openWorldHint: true },
132
+ async execute(_id, params, signal) {
133
+ const url = params.url.replace(/^http:\/\//, "https://");
134
+ const controller = new AbortController();
135
+ const timer = setTimeout(() => controller.abort(), 30_000);
136
+ signal?.addEventListener("abort", () => controller.abort(), { once: true });
137
+ try {
138
+ const res = await fetch(url, { signal: controller.signal, redirect: "follow", headers: { "user-agent": "pi-dev-team/1.0" } });
139
+ const type = res.headers.get("content-type") ?? "";
140
+ const raw = await res.text();
141
+ let text = type.includes("html") ? htmlToText(raw) : raw;
142
+ const truncated = text.length > FETCH_CAP;
143
+ if (truncated) text = `${text.slice(0, FETCH_CAP)}\n\n[truncated: ${text.length - FETCH_CAP} more characters]`;
144
+ const head = `URL: ${res.url}\nStatus: ${res.status}\nContent-Type: ${type}${params.prompt ? `\nLooking for: ${params.prompt}` : ""}\n\n`;
145
+ if (!res.ok) throw new Error(`${head}HTTP ${res.status}`);
146
+ return { content: [{ type: "text", text: head + text }], details: { status: res.status, truncated } };
147
+ } finally {
148
+ clearTimeout(timer);
149
+ }
150
+ },
151
+ });
152
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Synthetic Claude Code subagent transcripts.
3
+ *
4
+ * The SubagentStop hooks (review_verdict_recorder.py, subagent_completion_guard.py,
5
+ * task_completion_metrics.py) read a Claude-format sidechain transcript: the first record is the
6
+ * dispatch prompt (user turn), assistant records carry `attributionAgent`, `message.content` blocks,
7
+ * `message.stop_reason` and `message.usage`. pi children run with --no-session, so the subagent tool
8
+ * records the child's JSON event stream and writes this equivalent file before firing SubagentStop.
9
+ */
10
+ import { writeSessionFile } from "./session-files.ts";
11
+
12
+ interface PiContentBlock {
13
+ type: string;
14
+ text?: string;
15
+ name?: string;
16
+ id?: string;
17
+ arguments?: unknown;
18
+ thinking?: string;
19
+ }
20
+
21
+ export interface PiMessageLike {
22
+ role: string;
23
+ content?: unknown;
24
+ model?: string;
25
+ stopReason?: string;
26
+ toolCallId?: string;
27
+ toolName?: string;
28
+ isError?: boolean;
29
+ usage?: { input?: number; output?: number; cacheRead?: number; cacheWrite?: number };
30
+ }
31
+
32
+ const STOP_MAP: Record<string, string | null> = {
33
+ stop: "end_turn",
34
+ toolUse: "tool_use",
35
+ length: "max_tokens",
36
+ error: null,
37
+ aborted: null,
38
+ };
39
+
40
+ function contentBlocks(content: unknown): PiContentBlock[] {
41
+ if (typeof content === "string") return [{ type: "text", text: content }];
42
+ return Array.isArray(content) ? (content as PiContentBlock[]) : [];
43
+ }
44
+
45
+ export function buildTranscriptLines(opts: {
46
+ agentName: string;
47
+ agentId: string;
48
+ sessionId: string;
49
+ cwd: string;
50
+ prompt: string;
51
+ messages: PiMessageLike[];
52
+ }): string[] {
53
+ const base = { isSidechain: true, agentId: opts.agentId, sessionId: opts.sessionId, cwd: opts.cwd };
54
+ const attribution = `dev-team:${opts.agentName}`;
55
+ const lines: string[] = [
56
+ JSON.stringify({ ...base, type: "user", message: { role: "user", content: opts.prompt } }),
57
+ ];
58
+ for (const m of opts.messages) {
59
+ if (m.role === "assistant") {
60
+ const blocks = contentBlocks(m.content)
61
+ .map((b) => {
62
+ if (b.type === "text") return { type: "text", text: b.text ?? "" };
63
+ if (b.type === "toolCall") return { type: "tool_use", id: b.id, name: b.name, input: b.arguments ?? {} };
64
+ if (b.type === "thinking") return { type: "thinking", thinking: b.thinking ?? "" };
65
+ return undefined;
66
+ })
67
+ .filter(Boolean);
68
+ const u = m.usage ?? {};
69
+ lines.push(
70
+ JSON.stringify({
71
+ ...base,
72
+ type: "assistant",
73
+ attributionAgent: attribution,
74
+ message: {
75
+ role: "assistant",
76
+ model: m.model,
77
+ content: blocks,
78
+ stop_reason: m.stopReason ? (STOP_MAP[m.stopReason] ?? null) : null,
79
+ usage: {
80
+ input_tokens: u.input ?? 0,
81
+ output_tokens: u.output ?? 0,
82
+ cache_read_input_tokens: u.cacheRead ?? 0,
83
+ cache_creation_input_tokens: u.cacheWrite ?? 0,
84
+ },
85
+ },
86
+ }),
87
+ );
88
+ } else if (m.role === "toolResult") {
89
+ const text = contentBlocks(m.content)
90
+ .filter((b) => b.type === "text")
91
+ .map((b) => b.text ?? "")
92
+ .join("\n");
93
+ lines.push(
94
+ JSON.stringify({
95
+ ...base,
96
+ type: "user",
97
+ message: {
98
+ role: "user",
99
+ content: [{ type: "tool_result", tool_use_id: m.toolCallId, content: text, is_error: !!m.isError }],
100
+ },
101
+ }),
102
+ );
103
+ }
104
+ }
105
+ return lines;
106
+ }
107
+
108
+ export function writeTranscript(sessionId: string, agentId: string, lines: string[]): string {
109
+ return writeSessionFile(sessionId, "subagents", `agent-${agentId}.jsonl`, `${lines.join("\n")}\n`);
110
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * How this session's pi trust decision reaches the pi processes it starts (dev_team_subagent children
3
+ * and the claude shim). pi decides trust per working directory, so a granted decision covers exactly
4
+ * the session's directory, plus a worktree this session created of the repository rooted there. A
5
+ * declined decision is always forwarded, so a saved /trust entry or defaultProjectTrust cannot
6
+ * re-trust a child. Everywhere else the child decides for itself.
7
+ */
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
11
+
12
+ /** The directory as pi sees it: symlinks resolved, or just resolved when it does not exist. */
13
+ export function canonicalDir(dir: string): string {
14
+ try {
15
+ return fs.realpathSync(dir);
16
+ } catch {
17
+ return path.resolve(dir);
18
+ }
19
+ }
20
+
21
+ export interface ChildTrust {
22
+ /** pi's decision for the session (ctx.isProjectTrusted()). */
23
+ projectTrusted: boolean;
24
+ /** canonicalDir(ctx.cwd): the directory that decision is for. */
25
+ sessionDir: string;
26
+ }
27
+
28
+ /** This session's decision, as children inherit it. */
29
+ export function childTrustOf(ctx: Pick<ExtensionContext, "cwd" | "isProjectTrusted">): ChildTrust {
30
+ return { projectTrusted: ctx.isProjectTrusted(), sessionDir: canonicalDir(ctx.cwd) };
31
+ }
32
+
33
+ /**
34
+ * Flags for a child pi running in `runCwd`. `worktreeRepoRoot` is the repository a worktree was made
35
+ * from when the child runs in one this session created; it inherits trust only when that repository
36
+ * root is the session's own directory.
37
+ */
38
+ export function trustArgs(trust: ChildTrust, runCwd: string, worktreeRepoRoot?: string): string[] {
39
+ if (!trust.projectTrusted) return ["--no-approve"];
40
+ const here = canonicalDir(runCwd) === trust.sessionDir;
41
+ const ownWorktree = worktreeRepoRoot !== undefined && canonicalDir(worktreeRepoRoot) === trust.sessionDir;
42
+ return here || ownWorktree ? ["--approve"] : [];
43
+ }
44
+
45
+ /**
46
+ * Environment for the claude shim (bin/claude): DEV_TEAM_TRUSTED_DIR is set only when trusted, and
47
+ * the shim adds --approve only when it runs in exactly that directory; --no-approve rides in
48
+ * DEV_TEAM_PI_ARGS when declined.
49
+ */
50
+ export function shimTrustEnv(trust: ChildTrust, forwarded: string[]): { piArgs: string[]; trustedDir?: string } {
51
+ return trust.projectTrusted ? { piArgs: forwarded, trustedDir: trust.sessionDir } : { piArgs: [...forwarded, "--no-approve"] };
52
+ }
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Where a session's spend went, for every provider: the same runs the status line totals
3
+ * (session-spend.ts), grouped by model, by provider, by dispatched agent and provider, and by thread.
4
+ * Each group sums USD (pi's own cost, which every provider reports), the GitHub Copilot AI credits of
5
+ * the runs Copilot served (ai-credits.ts), and tokens. Shares are of USD. A run counts when it cost
6
+ * something or used tokens, so a free local model still shows; a run with neither is left out, and an
7
+ * empty breakdown means no usage at all. Amounts stay floats here; only the display rounds them.
8
+ */
9
+ import { creditsFor } from "./ai-credits.ts";
10
+ import { costUsd, type PiUsage, positiveFiniteOrZero, providerOf, type SpendRun } from "./session-spend.ts";
11
+ import type { SpendHistory } from "./usage-history.ts";
12
+
13
+ /** What a group of runs spent. */
14
+ export interface SpendAmounts {
15
+ usd: number;
16
+ /** AI credits of the runs GitHub Copilot served; 0 when it served none. */
17
+ credits: number;
18
+ tokens: number;
19
+ }
20
+
21
+ export interface UsageRow<L extends string = string> extends SpendAmounts {
22
+ label: L;
23
+ /** Fraction (0 to 1) of the USD of the grouping this row belongs to; 0 when that grouping cost nothing. */
24
+ share: number;
25
+ }
26
+
27
+ /** How a thread is named on screen; the overlay's thread split draws the same closed set (THREAD_ORDER). */
28
+ export type ThreadLabel = "main" | "subagents" | "overhead";
29
+
30
+ export interface ThreadRow extends UsageRow<ThreadLabel> {
31
+ /** The SpendRun thread behind the label ("subagents" is "subagent"). */
32
+ thread: SpendRun["thread"];
33
+ }
34
+
35
+ /** One dispatched agent's spend on one provider; `label` is the agent's name. */
36
+ export interface AgentRow extends UsageRow {
37
+ /** The provider that served this part of the agent's spend. */
38
+ provider: string;
39
+ }
40
+
41
+ export interface UsageBreakdown {
42
+ /** Every run's spend; the sum of the `byModel` rows. */
43
+ total: SpendAmounts;
44
+ /** "provider/model" rows. */
45
+ byModel: UsageRow[];
46
+ byProvider: UsageRow[];
47
+ /** One row per dispatched agent and provider (main-thread turns and overhead are not agents); shares are of the agents' own USD. */
48
+ byAgent: AgentRow[];
49
+ /** "main", "subagents" and "overhead", whichever spent, ranked like the other groupings. */
50
+ byThread: ThreadRow[];
51
+ }
52
+
53
+ export const THREAD_LABEL: Record<SpendRun["thread"], ThreadLabel> = { main: "main", subagent: "subagents", overhead: "overhead" };
54
+ /** The threads in the order the overlay's thread split draws them, so a glyph always means the same thread. */
55
+ export const THREAD_ORDER: readonly ThreadLabel[] = Object.values(THREAD_LABEL);
56
+ /** Below this share a non-zero row displays as "<1%". */
57
+ const TINY_SHARE = 0.01;
58
+ /** The finest USD amount the display shows; below it a cost reads as "<$0.01". */
59
+ const USD_CENT = 0.01;
60
+
61
+ /** A run's tokens: input, output and both cache directions. */
62
+ export function runTokens(usage: PiUsage): number {
63
+ return positiveFiniteOrZero(usage.input) + positiveFiniteOrZero(usage.output) + positiveFiniteOrZero(usage.cacheRead) + positiveFiniteOrZero(usage.cacheWrite);
64
+ }
65
+
66
+ /** A run's USD, AI credits (from that same USD, when Copilot served it) and tokens. */
67
+ function runAmounts(run: SpendRun): SpendAmounts {
68
+ const usd = positiveFiniteOrZero(costUsd(run.usage));
69
+ return { usd, credits: creditsFor(run.model, usd), tokens: runTokens(run.usage) };
70
+ }
71
+
72
+ const ZERO: SpendAmounts = { usd: 0, credits: 0, tokens: 0 };
73
+ const plus = (a: SpendAmounts, b: SpendAmounts): SpendAmounts => ({ usd: a.usd + b.usd, credits: a.credits + b.credits, tokens: a.tokens + b.tokens });
74
+
75
+ /** A group's label and what it spent, before ranking. */
76
+ interface Group<L extends string, E> {
77
+ label: L;
78
+ /** Breaks ties between groups with the same label (an agent on two providers). */
79
+ tieBreak: string;
80
+ amounts: SpendAmounts;
81
+ extra: E;
82
+ }
83
+
84
+ /** Rows by USD, largest first, then by tokens, then by name; each with its share of the groups' USD. */
85
+ function rank<L extends string, E>(groups: Iterable<Group<L, E>>): (UsageRow<L> & E)[] {
86
+ const list = [...groups];
87
+ const totalUsd = list.reduce((sum, g) => sum + g.amounts.usd, 0);
88
+ return list
89
+ .sort((a, b) => b.amounts.usd - a.amounts.usd || b.amounts.tokens - a.amounts.tokens || a.label.localeCompare(b.label, "en") || a.tieBreak.localeCompare(b.tieBreak, "en"))
90
+ .map((g) => ({ ...g.extra, label: g.label, ...g.amounts, share: totalUsd > 0 ? g.amounts.usd / totalUsd : 0 }));
91
+ }
92
+
93
+ /** Sums runs into groups by key, keeping each group's label and extra fields from its first run. */
94
+ class Grouper<L extends string, E> {
95
+ private readonly groups = new Map<string, Group<L, E>>();
96
+ add(key: string, label: L, amounts: SpendAmounts, extra: E, tieBreak = ""): void {
97
+ const group = this.groups.get(key);
98
+ if (group) group.amounts = plus(group.amounts, amounts);
99
+ else this.groups.set(key, { label, tieBreak, amounts, extra });
100
+ }
101
+ ranked(): (UsageRow<L> & E)[] {
102
+ return rank(this.groups.values());
103
+ }
104
+ }
105
+
106
+ /** False when nothing was spent: no USD and no tokens. */
107
+ export function hasUsage(amounts: SpendAmounts): boolean {
108
+ return amounts.usd > 0 || amounts.tokens > 0;
109
+ }
110
+
111
+ export function usageBreakdown(runs: Iterable<SpendRun>): UsageBreakdown {
112
+ const models = new Grouper<string, object>();
113
+ const providers = new Grouper<string, object>();
114
+ const agents = new Grouper<string, { provider: string }>();
115
+ const threads = new Grouper<ThreadLabel, { thread: SpendRun["thread"] }>();
116
+ for (const run of runs) {
117
+ const amounts = runAmounts(run);
118
+ if (!hasUsage(amounts)) continue;
119
+ const provider = providerOf(run.model);
120
+ models.add(run.model, run.model, amounts, {});
121
+ providers.add(provider, provider, amounts, {});
122
+ threads.add(run.thread, THREAD_LABEL[run.thread], amounts, { thread: run.thread });
123
+ // Keyed on the pair, so no agent name can collide with another agent and provider.
124
+ if (run.thread === "subagent") agents.add(JSON.stringify([run.agent, provider]), run.agent, amounts, { provider }, provider);
125
+ }
126
+ const byModel = models.ranked();
127
+ return {
128
+ total: byModel.reduce<SpendAmounts>((sum, row) => plus(sum, row), ZERO),
129
+ byModel,
130
+ byProvider: providers.ranked(),
131
+ byAgent: agents.ranked(),
132
+ byThread: threads.ranked(),
133
+ };
134
+ }
135
+
136
+ /** What this month's load produced. */
137
+ export interface MonthSnapshot {
138
+ breakdown: UsageBreakdown;
139
+ /** Session files that could not be read. */
140
+ unreadable: number;
141
+ /** When the load finished; the header says "as of" this time. */
142
+ loadedAt: Date;
143
+ }
144
+
145
+ /** The snapshot of a finished load: the breakdown of its runs, the files it could not read, and when it finished. */
146
+ export function monthSnapshot(history: SpendHistory, loadedAt: Date): MonthSnapshot {
147
+ return { breakdown: usageBreakdown(history.records.map((r) => r.run)), unreadable: history.unreadable, loadedAt };
148
+ }
149
+
150
+ /** "83.3%", "<1%" for a non-zero share under 1% so a small row never reads as 0.0%, and "0%" for none. */
151
+ export function formatShare(share: number): string {
152
+ if (!(share > 0)) return "0%";
153
+ return share < TINY_SHARE ? "<1%" : `${(share * 100).toFixed(1)}%`;
154
+ }
155
+
156
+ /** "$4.20", "$1,234.50", "<$0.01" for a cost under a cent, "$0.00" for none. */
157
+ export function formatUsd(usd: number): string {
158
+ if (!(usd > 0)) return "$0.00";
159
+ if (Number(usd.toFixed(2)) < USD_CENT) return "<$0.01";
160
+ return `$${usd.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
161
+ }
162
+
163
+ const TOKEN_UNITS: readonly (readonly [number, string])[] = [
164
+ [1e9, "B"],
165
+ [1e6, "M"],
166
+ [1e3, "k"],
167
+ ];
168
+
169
+ /** "320 tok", "85.3k tok", "1.2M tok". */
170
+ export function formatTokens(tokens: number): string {
171
+ for (const [size, unit] of TOKEN_UNITS) {
172
+ const scaled = tokens / size;
173
+ if (Number(scaled.toFixed(1)) >= 1) return `${Number(scaled.toFixed(1)).toLocaleString("en-US")}${unit} tok`;
174
+ }
175
+ return `${Math.round(tokens)} tok`;
176
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Block-character ranked bar chart for the /dev-team usage overlay (barChartLines); the stacked
3
+ * splits are usage-split-bar.ts. Pure string rendering: every line is built from plain
4
+ * text, measured with pi-tui's visibleWidth, cut where needed and only then styled, so a line never
5
+ * exceeds the width it was asked for and colour comes from the injected style alone. Formatting
6
+ * (USD, credits, tokens, share) is injected too, which keeps this module free of the breakdown and
7
+ * theme code that feeds it.
8
+ */
9
+ import { visibleWidth } from "@earendil-works/pi-tui";
10
+ import { cutToWidth, toSingleLine } from "./terminal-text.ts";
11
+
12
+ export interface ChartRow {
13
+ label: string;
14
+ /** The bar's length and the first value column. */
15
+ usd: number;
16
+ /** AI credits; a column of its own when any row has some. */
17
+ credits: number;
18
+ tokens: number;
19
+ /** Fraction (0 to 1), shown through `format.share`. */
20
+ share: number;
21
+ }
22
+
23
+ export interface ChartStyle {
24
+ /** Colours a bar. */
25
+ bar(text: string): string;
26
+ /** De-emphasises the secondary columns (credits, tokens, share). */
27
+ muted(text: string): string;
28
+ }
29
+
30
+ export interface ChartFormat {
31
+ usd(usd: number): string;
32
+ /** "" for a row without credits worth showing; the cell stays blank. */
33
+ credits(credits: number): string;
34
+ tokens(tokens: number): string;
35
+ share(share: number): string;
36
+ }
37
+
38
+ export interface BarChartOptions {
39
+ /** Terminal columns every returned line must fit in. */
40
+ width: number;
41
+ /** Most lines to return; rows beyond that fold into one "other (N)" line that takes the last slot. */
42
+ maxRows: number;
43
+ format: ChartFormat;
44
+ /**
45
+ * Which optional columns the rows want, decided by the caller over all rows (before any fold into
46
+ * "other"), so the overlay and the text summary apply one rule. Share is always wanted.
47
+ */
48
+ wantedColumns: { credits: boolean; tokens: boolean };
49
+ style: ChartStyle;
50
+ }
51
+
52
+ const COLUMN_GAP = " ";
53
+ const GAP_WIDTH = COLUMN_GAP.length;
54
+ /** Gaps between the label, bar and USD columns; each optional column adds one more. */
55
+ const GAPS_LABEL_BAR_USD = 2;
56
+ const MAX_BAR_CELLS = 30;
57
+ /** `▏` to `▉`: one to seven eighths of a cell; a full cell is `█`. */
58
+ const PARTIAL_BLOCKS = "▏▎▍▌▋▊▉";
59
+ export const FULL_BLOCK = "█";
60
+ const EIGHTHS_PER_CELL = 8;
61
+ /** Narrowest label and bar worth drawing; below these the layout drops a column instead of squeezing. */
62
+ const MIN_LABEL_CELLS = 6;
63
+ const MIN_BAR_CELLS = 6;
64
+ /** `eighths` eighths of a cell as glyphs: whole cells of `█`, then one partial block. */
65
+ function barGlyphs(eighths: number): string {
66
+ const rest = eighths % EIGHTHS_PER_CELL;
67
+ return FULL_BLOCK.repeat(Math.floor(eighths / EIGHTHS_PER_CELL)) + (rest ? PARTIAL_BLOCKS[rest - 1] : "");
68
+ }
69
+
70
+ /** Bar length in eighths of a cell; any non-zero value gets at least one so it never vanishes. */
71
+ function barEighths(value: number, max: number, cells: number): number {
72
+ if (value <= 0 || max <= 0) return 0;
73
+ return Math.max(1, Math.round((value / max) * cells * EIGHTHS_PER_CELL));
74
+ }
75
+
76
+ const padEnd = (text: string, width: number) => text + " ".repeat(Math.max(0, width - visibleWidth(text)));
77
+ const padStart = (text: string, width: number) => " ".repeat(Math.max(0, width - visibleWidth(text))) + text;
78
+
79
+ /** The columns after the bar, in drop order: the first one listed goes last. */
80
+ const OPTIONAL_COLUMNS = ["credits", "tokens", "share"] as const;
81
+ type OptionalColumn = (typeof OPTIONAL_COLUMNS)[number];
82
+
83
+ interface Columns {
84
+ /** 0 drops the label column and its gap. */
85
+ label: number;
86
+ /** 0 drops the bar column. */
87
+ bar: number;
88
+ /** The optional columns kept, each at its natural width. */
89
+ shown: ReadonlySet<OptionalColumn>;
90
+ /** Narrower than the natural USD width only when the USD value alone overflows the line. */
91
+ usd: number;
92
+ }
93
+
94
+ /**
95
+ * Splits `width` across the columns. The label truncates first (down to MIN_LABEL_CELLS, or its
96
+ * natural width when shorter); when the bar would fall below MIN_BAR_CELLS the optional columns go,
97
+ * share first, then tokens, then credits; then the bar, then the label, leaving the USD value alone,
98
+ * which is cut (with an ellipsis) only when it overflows the line by itself. USD is never dropped.
99
+ */
100
+ function fitColumns(width: number, natural: { label: number; usd: number } & Record<OptionalColumn, number>, wanted: readonly OptionalColumn[]): Columns {
101
+ const minLabel = Math.min(natural.label, MIN_LABEL_CELLS);
102
+ for (let keep = wanted.length; keep >= 0; keep--) {
103
+ const shown = new Set(wanted.slice(0, keep));
104
+ const optionalWidth = [...shown].reduce((sum, column) => sum + natural[column] + GAP_WIDTH, 0);
105
+ const room = width - natural.usd - optionalWidth - GAPS_LABEL_BAR_USD * GAP_WIDTH;
106
+ const label = Math.min(natural.label, room - MIN_BAR_CELLS);
107
+ if (label >= minLabel) return { label, bar: Math.min(MAX_BAR_CELLS, room - label), shown, usd: natural.usd };
108
+ }
109
+ const none = new Set<OptionalColumn>();
110
+ const label = Math.min(natural.label, width - natural.usd - GAP_WIDTH);
111
+ if (label > 0) return { label, bar: 0, shown: none, usd: natural.usd };
112
+ return { label: 0, bar: 0, shown: none, usd: Math.max(0, Math.min(natural.usd, width)) };
113
+ }
114
+
115
+ /** The first `maxRows - 1` rows, then "other (N)" summing the rest; all rows when they fit. */
116
+ function foldRows(rows: readonly ChartRow[], maxRows: number): ChartRow[] {
117
+ if (rows.length <= maxRows) return [...rows];
118
+ const kept = rows.slice(0, Math.max(0, maxRows - 1));
119
+ const folded = rows.slice(kept.length);
120
+ const sum = (pick: (r: ChartRow) => number) => folded.reduce((total, r) => total + pick(r), 0);
121
+ return [...kept, { label: `other (${folded.length})`, usd: sum((r) => r.usd), credits: sum((r) => r.credits), tokens: sum((r) => r.tokens), share: sum((r) => r.share) }];
122
+ }
123
+
124
+ /** One line per row: label, bar scaled to the largest USD, USD, then the wanted optional columns (credits, tokens) and share. */
125
+ export function barChartLines(allRows: readonly ChartRow[], { width, maxRows, format, wantedColumns, style }: BarChartOptions): string[] {
126
+ const rows = (maxRows > 0 ? foldRows(allRows, maxRows) : []).map((r) => ({ ...r, label: toSingleLine(r.label) }));
127
+ if (!rows.length) return [];
128
+ const cellsOf: Record<OptionalColumn, string[]> = {
129
+ credits: rows.map((r) => format.credits(r.credits)),
130
+ tokens: rows.map((r) => format.tokens(r.tokens)),
131
+ share: rows.map((r) => format.share(r.share)),
132
+ };
133
+ const usdCells = rows.map((r) => format.usd(r.usd));
134
+ const widest = (cells: readonly string[]) => Math.max(...cells.map(visibleWidth));
135
+ const natural = { label: widest(rows.map((r) => r.label)), usd: widest(usdCells), credits: widest(cellsOf.credits), tokens: widest(cellsOf.tokens), share: widest(cellsOf.share) };
136
+ const wanted = OPTIONAL_COLUMNS.filter((column) => column === "share" || wantedColumns[column]);
137
+ const columns = fitColumns(width, natural, wanted);
138
+ const max = Math.max(...rows.map((r) => r.usd));
139
+
140
+ return rows.map((row, i) => {
141
+ const cells: string[] = [];
142
+ if (columns.label) cells.push(padEnd(cutToWidth(row.label, columns.label), columns.label));
143
+ if (columns.bar) {
144
+ const bar = barGlyphs(barEighths(row.usd, max, columns.bar));
145
+ cells.push(style.bar(bar) + " ".repeat(columns.bar - visibleWidth(bar)));
146
+ }
147
+ cells.push(padStart(cutToWidth(usdCells[i], columns.usd), columns.usd));
148
+ for (const column of OPTIONAL_COLUMNS) {
149
+ if (columns.shown.has(column)) cells.push(style.muted(padStart(cellsOf[column][i], natural[column])));
150
+ }
151
+ return cells.join(COLUMN_GAP);
152
+ });
153
+ }