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,236 @@
1
+ /**
2
+ * dev-team configuration.
3
+ *
4
+ * Merged, later wins:
5
+ * 1. built-in defaults
6
+ * 2. ~/.pi/agent/dev-team.json (user)
7
+ * 3. <project>/.pi/dev-team.json (project, committed)
8
+ * 4. <project>/.pi/dev-team.local.json (project, personal, git-ignored)
9
+ */
10
+ import * as fs from "node:fs";
11
+ import * as path from "node:path";
12
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
13
+ import { readSmallFile } from "./safe-read.ts";
14
+
15
+ export type Tier = "opus" | "sonnet" | "haiku" | "fable" | string;
16
+
17
+ export interface HookConfig {
18
+ /** Master switch for the Python hook bridge. */
19
+ enabled: boolean;
20
+ /** Hook script basenames (without .py) to skip. Replaces the default list when set. */
21
+ disabled: string[];
22
+ /** Hook script basenames to force-enable even if in the default disabled list. */
23
+ enable: string[];
24
+ /** Append advisory hook output (exit 0 stdout) to the tool result the model sees. */
25
+ outputToModel: boolean;
26
+ /** Per-hook timeout in seconds (fail-open on timeout). */
27
+ timeoutSec: number;
28
+ }
29
+
30
+ export const GITHUB_STYLE_MODES = ["block", "warn", "off"] as const;
31
+ export type GitHubStyleMode = (typeof GITHUB_STYLE_MODES)[number];
32
+
33
+ export interface DevTeamConfig {
34
+ /** Agent model tier -> "provider/model-id" or "inherit" (use the dispatching session's model). */
35
+ models: Record<Tier, string>;
36
+ /** Agent `effort` -> pi thinking level. */
37
+ thinking: Record<string, string>;
38
+ /** Maximum concurrently running subagent processes (across all calls). */
39
+ maxParallelAgents: number;
40
+ /** Maximum nesting depth of subagents (a subagent dispatching a subagent is depth 2). */
41
+ maxSubagentDepth: number;
42
+ /** Wall-clock limit per subagent in seconds (0 = none). */
43
+ subagentTimeoutSec: number;
44
+ hooks: HookConfig;
45
+ /** Run hooks/post_format.py after write/edit (what /setup's formatter hook did). */
46
+ autoFormat: boolean;
47
+ /** Pull request and issue text that breaks the GitHub style rules: block the gh call once ("block"), only note it ("warn"), or skip the check and the style guide ("off"). */
48
+ githubStyle: GitHubStyleMode;
49
+ /** How dev-team skills are advertised in the system prompt. */
50
+ skillIndex: "compact" | "full" | "off";
51
+ /** Max description characters per skill in the compact index. */
52
+ skillIndexChars: number;
53
+ /** Put the `claude` -> `pi` CLI shim on PATH for scripts that call `claude -p`. */
54
+ claudeShim: boolean;
55
+ /** Extra environment variables for tools, hooks, scripts and subagents (e.g. DEV_TEAM_MAX_PARALLEL_BUILDS). */
56
+ env: Record<string, string>;
57
+ }
58
+
59
+ /**
60
+ * Hooks off by default. See PORTING.md section 4.
61
+ * - replaced natively by the extension: cost_meter, subagent_skill_context
62
+ * - need Claude transcripts / Claude-only config: code_intelligence_*, phase_marker, session_learning_trigger,
63
+ * mcp_json_repowise_nudge, version_check
64
+ * - only act inside the upstream monorepo: the rest
65
+ */
66
+ export const DEFAULT_DISABLED_HOOKS = [
67
+ "cost_meter",
68
+ "subagent_skill_context",
69
+ "code_intelligence_nudge",
70
+ "code_intelligence_turn_mark",
71
+ "phase_marker",
72
+ "session_learning_trigger",
73
+ "mcp_json_repowise_nudge",
74
+ "version_check",
75
+ "contract_version_guard",
76
+ "pre_commit_knowledge_index",
77
+ "knowledge_index",
78
+ "skills_index",
79
+ "scan_bash_command_for_banned_scripts",
80
+ "scan_worktree_for_banned_scripts",
81
+ "eval_compliance_check",
82
+ ];
83
+
84
+ export const DEFAULT_CONFIG: DevTeamConfig = {
85
+ models: { opus: "inherit", sonnet: "inherit", haiku: "inherit", fable: "inherit" },
86
+ thinking: { low: "low", medium: "medium", high: "high", xhigh: "xhigh", max: "max" },
87
+ maxParallelAgents: 6,
88
+ maxSubagentDepth: 2,
89
+ subagentTimeoutSec: 3600,
90
+ hooks: { enabled: true, disabled: DEFAULT_DISABLED_HOOKS, enable: [], outputToModel: true, timeoutSec: 60 },
91
+ autoFormat: false,
92
+ githubStyle: "block",
93
+ skillIndex: "compact",
94
+ skillIndexChars: 220,
95
+ claudeShim: true,
96
+ env: {},
97
+ };
98
+
99
+ /** Tier presets offered by `/dev-team models`. Values are provider/model ids from pi's catalog. */
100
+ export const MODEL_PRESETS: Record<string, Record<string, string>> = {
101
+ "github-copilot": {
102
+ opus: "github-copilot/claude-opus-5.5",
103
+ sonnet: "github-copilot/claude-sonnet-5.5",
104
+ haiku: "github-copilot/claude-haiku-4.5",
105
+ fable: "github-copilot/claude-fable-5.1",
106
+ },
107
+ anthropic: {
108
+ opus: "anthropic/claude-opus-5-5",
109
+ sonnet: "anthropic/claude-sonnet-5-5",
110
+ haiku: "anthropic/claude-haiku-4-5",
111
+ fable: "anthropic/claude-fable-5-1",
112
+ },
113
+ inherit: { opus: "inherit", sonnet: "inherit", haiku: "inherit", fable: "inherit" },
114
+ };
115
+
116
+ export function userConfigPath(): string {
117
+ return path.join(getAgentDir(), "dev-team.json");
118
+ }
119
+
120
+ export function projectConfigPath(cwd: string, local = false): string {
121
+ return path.join(cwd, ".pi", local ? "dev-team.local.json" : "dev-team.json");
122
+ }
123
+
124
+ function readJson(file: string): Record<string, unknown> | undefined {
125
+ const text = readSmallFile(file);
126
+ if (text === undefined) return undefined;
127
+ try {
128
+ const parsed = JSON.parse(text);
129
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
130
+ } catch {
131
+ return undefined;
132
+ }
133
+ }
134
+
135
+ function isPlainObject(v: unknown): v is Record<string, unknown> {
136
+ return !!v && typeof v === "object" && !Array.isArray(v);
137
+ }
138
+
139
+ /** Deep merge for plain objects; arrays and scalars replace. */
140
+ export function mergeConfig<T>(base: T, override: unknown): T {
141
+ if (!isPlainObject(override)) return base;
142
+ const out: Record<string, unknown> = { ...(base as Record<string, unknown>) };
143
+ for (const [k, v] of Object.entries(override)) {
144
+ const cur = out[k];
145
+ out[k] = isPlainObject(cur) && isPlainObject(v) ? mergeConfig(cur, v) : v;
146
+ }
147
+ return out as T;
148
+ }
149
+
150
+ /**
151
+ * A project's config may set only these dev-team tuning settings, each to a plain number, word or
152
+ * flag. pi asks about trust only when a repo has pi-protected files (.pi/settings.json, .pi/extensions,
153
+ * ...), so a repo with just a .pi/dev-team.json is trusted without a prompt. Its env must therefore not
154
+ * reach PATH, NODE_OPTIONS or PYTHONPATH, any file path the port reads or runs (DEV_TEAM_PY_CACHE is
155
+ * executed by hooks/py.sh), a program choice, or a gate bypass (DEV_TEAM_AUTO_APPROVE,
156
+ * DEV_TEAM_GUARD_OVERRIDE, *_SKIP, a threshold whose 0 disables a guard). Those stay available in the
157
+ * user's own config and environment.
158
+ */
159
+ export const PROJECT_ENV_SETTINGS: ReadonlySet<string> = new Set([
160
+ "DEV_TEAM_MAX_PARALLEL_BUILDS",
161
+ "DEV_TEAM_MAX_PARALLEL_REVIEW_AGENTS",
162
+ "DEV_TEAM_AUTO_REVIEW",
163
+ "DEV_TEAM_AUTO_REVIEW_THRESHOLD",
164
+ "DEV_TEAM_REPO_REVIEW_PERCENT_THRESHOLD",
165
+ "DEV_TEAM_REPO_REVIEW_MIN_ADDED_LINES",
166
+ "DEV_TEAM_REPO_REVIEW_MAX_ADDED_LINES",
167
+ "DEV_TEAM_REVIEW_CONTEXT_PACK",
168
+ "DEV_TEAM_WORKTREE_BASE_FRESH",
169
+ "DEV_TEAM_AUTOCOMPACT_NUDGE",
170
+ "DEV_TEAM_COST_METER",
171
+ "DEV_TEAM_TASK_METRICS",
172
+ "DEV_TEAM_REVIEW_VALUE",
173
+ "DEV_TEAM_TELEMETRY",
174
+ ]);
175
+ const PLAIN_SETTING_VALUE = /^[A-Za-z0-9._-]{0,64}$/;
176
+
177
+ export function isProjectEnvSettingAllowed(key: string, value: unknown): boolean {
178
+ return PROJECT_ENV_SETTINGS.has(key) && (typeof value === "string" || typeof value === "number" || typeof value === "boolean") && PLAIN_SETTING_VALUE.test(String(value));
179
+ }
180
+
181
+ /**
182
+ * A project config file as it may apply: env limited to PROJECT_ENV_SETTINGS (an env that is not an
183
+ * object is dropped whole), and no `hooks` at all, since hooks include the guards; hooks are set in the
184
+ * user's own config. `ignored` names everything left out, as `env.KEY`, `env` or `hooks`.
185
+ */
186
+ export function filterProjectConfig(data: Record<string, unknown>): { data: Record<string, unknown>; ignored: string[] } {
187
+ const ignored: string[] = [];
188
+ const { env, hooks, ...rest } = data;
189
+ const out: Record<string, unknown> = rest;
190
+ if (hooks !== undefined) ignored.push("hooks");
191
+ if (env === undefined) return { data: out, ignored };
192
+ if (!isPlainObject(env)) return { data: out, ignored: [...ignored, "env"] };
193
+ const entries = Object.entries(env);
194
+ out.env = Object.fromEntries(entries.filter(([k, v]) => isProjectEnvSettingAllowed(k, v)));
195
+ for (const [k, v] of entries) if (!isProjectEnvSettingAllowed(k, v)) ignored.push(`env.${k}`);
196
+ return { data: out, ignored };
197
+ }
198
+
199
+ /**
200
+ * User config, then the project's .pi/dev-team.json and .pi/dev-team.local.json. Project files are
201
+ * filtered (filterProjectConfig), so callers pass `includeProject: ctx.isProjectTrusted()`.
202
+ */
203
+ export function loadConfig(
204
+ cwd: string,
205
+ opts: { includeProject: boolean; userConfigFile?: string },
206
+ ): { config: DevTeamConfig; sources: string[]; ignoredProjectSettings: string[] } {
207
+ let config = DEFAULT_CONFIG;
208
+ const sources: string[] = [];
209
+ const ignoredProjectSettings: string[] = [];
210
+ const userFile = opts.userConfigFile ?? userConfigPath();
211
+ const projectFiles = opts.includeProject ? [projectConfigPath(cwd), projectConfigPath(cwd, true)] : [];
212
+ for (const file of [userFile, ...projectFiles]) {
213
+ const raw = readJson(file);
214
+ if (!raw) continue;
215
+ const { data, ignored } = file === userFile ? { data: raw, ignored: [] } : filterProjectConfig(raw);
216
+ if ("githubStyle" in data && !(GITHUB_STYLE_MODES as readonly unknown[]).includes(data.githubStyle)) delete data.githubStyle;
217
+ config = mergeConfig(config, data);
218
+ sources.push(file);
219
+ ignoredProjectSettings.push(...ignored);
220
+ }
221
+ return { config, sources, ignoredProjectSettings };
222
+ }
223
+
224
+ /** Read-modify-write one config file (used by /dev-team models). */
225
+ export function updateConfigFile(file: string, patch: Record<string, unknown>): void {
226
+ const current = readJson(file) ?? {};
227
+ const next = mergeConfig(current, patch);
228
+ fs.mkdirSync(path.dirname(file), { recursive: true });
229
+ fs.writeFileSync(file, `${JSON.stringify(next, null, 2)}\n`, "utf-8");
230
+ }
231
+
232
+ export function isHookEnabled(config: DevTeamConfig, hookName: string): boolean {
233
+ if (!config.hooks.enabled) return false;
234
+ if (config.hooks.enable.includes(hookName)) return true;
235
+ return !config.hooks.disabled.includes(hookName);
236
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The title and body that `gh pr|issue create|edit|comment` commands in a bash command line send.
3
+ * Only literal values are returned: a value the shell computes is left undefined, so it is not checked.
4
+ */
5
+ import * as path from "node:path";
6
+ import { readBoundedFile } from "./safe-read.ts";
7
+ import { type ShellSegment, type ShellWord, scanShell } from "./shell-scan.ts";
8
+
9
+ export const GH_TEXT_KINDS = ["pr", "issue", "comment"] as const;
10
+ export type GhTextKind = (typeof GH_TEXT_KINDS)[number];
11
+
12
+ /** A body file is read up to this size: 100,000 characters of UTF-8 take at most 4 bytes each. */
13
+ export const MAX_BODY_FILE_BYTES = 400_000;
14
+
15
+ export interface GhText {
16
+ kind: GhTextKind;
17
+ title?: string;
18
+ body?: string;
19
+ /** The body file is larger than MAX_BODY_FILE_BYTES, so it was not read. */
20
+ bodyFileTooLarge?: boolean;
21
+ }
22
+
23
+ type BodyValue = Pick<GhText, "body" | "bodyFileTooLarge">;
24
+
25
+ const TITLE_FLAGS = new Set(["--title", "-t"]);
26
+ const BODY_FLAGS = new Set(["--body", "-b"]);
27
+ const BODY_FILE_FLAGS = new Set(["--body-file", "-F"]);
28
+ const GH_GROUPS = new Set(["pr", "issue"]);
29
+ const GH_ACTIONS = new Set(["create", "edit", "comment"]);
30
+ /** Words that can come before the command itself in a simple command. */
31
+ const COMMAND_PREFIXES = new Set(["if", "then", "elif", "else", "do", "while", "until", "!", "{", "time", "env", "command", "exec", "nohup"]);
32
+ const ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
33
+
34
+ /** The body a `--body-file` value gives: a file relative to `cwd`, or stdin for `-`. */
35
+ function bodyFromFile(value: ShellWord, stdin: string | undefined, cwd: string): BodyValue {
36
+ if (value.dynamic) return { body: undefined };
37
+ if (value.text === "-") return { body: stdin };
38
+ const result = readBoundedFile(path.resolve(cwd, value.text), MAX_BODY_FILE_BYTES);
39
+ if ("text" in result) return { body: result.text };
40
+ return result.skipped === "too-large" ? { body: undefined, bodyFileTooLarge: true } : { body: undefined };
41
+ }
42
+
43
+ /** Literal stdin from a `<<'EOF'` heredoc or a `<<<` here-string in the command's arguments. */
44
+ function readStdin(args: ShellWord[]): string | undefined {
45
+ for (let argIndex = 0; argIndex < args.length; argIndex++) {
46
+ const arg = args[argIndex];
47
+ if (arg.redirect === "heredoc") return arg.dynamic ? undefined : arg.heredocBody;
48
+ if (arg.redirect === "here-string") {
49
+ const value = args[argIndex + 1];
50
+ return value && !value.dynamic ? `${value.text}\n` : undefined;
51
+ }
52
+ }
53
+ return undefined;
54
+ }
55
+
56
+ /** The kind and arguments when the segment is `[prefix ...] [NAME=value ...] gh pr|issue create|edit|comment ...`. */
57
+ function locateGhCommand(segment: ShellSegment): { kind: GhTextKind; args: ShellWord[] } | undefined {
58
+ let commandIndex = 0;
59
+ const isPrefix = (word: ShellWord) => (!word.dynamic && COMMAND_PREFIXES.has(word.text)) || ASSIGNMENT.test(word.text);
60
+ while (commandIndex < segment.length && isPrefix(segment[commandIndex])) commandIndex++;
61
+ const [command, group, action] = segment.slice(commandIndex, commandIndex + 3);
62
+ if (!command || command.dynamic || path.basename(command.text) !== "gh") return undefined;
63
+ if (!group || !GH_GROUPS.has(group.text) || !action || !GH_ACTIONS.has(action.text)) return undefined;
64
+ const kind: GhTextKind = action.text === "comment" ? "comment" : group.text === "pr" ? "pr" : "issue";
65
+ return { kind, args: segment.slice(commandIndex + 3) };
66
+ }
67
+
68
+ /** Title and body from the flags. When a flag is given twice, the last one wins, as in gh. */
69
+ function readTitleAndBody(kind: GhTextKind, args: ShellWord[], cwd: string): GhText {
70
+ const stdin = readStdin(args);
71
+ let titleValue: Pick<GhText, "title"> = {};
72
+ let bodyValue: BodyValue = {};
73
+ for (let argIndex = 0; argIndex < args.length; argIndex++) {
74
+ const arg = args[argIndex];
75
+ if (arg.redirect) {
76
+ if (arg.redirect === "here-string") argIndex++;
77
+ continue;
78
+ }
79
+ const inlineFlag = /^(--[a-z-]+)=([\s\S]*)$/.exec(arg.text);
80
+ const flag = inlineFlag ? inlineFlag[1] : arg.text;
81
+ if (!TITLE_FLAGS.has(flag) && !BODY_FLAGS.has(flag) && !BODY_FILE_FLAGS.has(flag)) continue;
82
+ const value: ShellWord | undefined = inlineFlag ? { text: inlineFlag[2], dynamic: arg.dynamic } : args[++argIndex];
83
+ if (!value || value.redirect) continue;
84
+ if (TITLE_FLAGS.has(flag)) titleValue = { title: value.dynamic ? undefined : value.text };
85
+ else if (BODY_FLAGS.has(flag)) bodyValue = { body: value.dynamic ? undefined : value.text };
86
+ else bodyValue = bodyFromFile(value, stdin, cwd);
87
+ }
88
+ return { kind, ...titleValue, ...bodyValue };
89
+ }
90
+
91
+ /**
92
+ * The title and body that each `gh pr|issue create|edit|comment` in a bash command sends. A value the
93
+ * shell computes ($VAR, `$(git log ...)`, an unquoted heredoc with $ in it) is left undefined and not
94
+ * checked. `$(cat <<'EOF' ...)`, `--body-file -` with a heredoc or here-string, and a body file
95
+ * (relative to `cwd`) are read.
96
+ */
97
+ export function extractGhTexts(command: string, cwd: string): GhText[] {
98
+ if (!/\bgh\b/.test(command)) return [];
99
+ return scanShell(command).flatMap((segment) => {
100
+ const located = locateGhCommand(segment);
101
+ return located ? [readTitleAndBody(located.kind, located.args, cwd)] : [];
102
+ });
103
+ }
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Writing style for the pull requests, issues and comments that the team opens on GitHub. The rules
3
+ * join two sources: plain English after ASD-STE100 (AminBlg/SimpleEnglish: short sentences, active
4
+ * voice, no hedges, no filler) and a layout for a reader with little attention to spare
5
+ * (ayghri/i-have-adhd: the point first, short lists, one next step, details out of the way).
6
+ *
7
+ * `styleGuideFor` gives the rules for the system prompt of every session and subagent.
8
+ * `createStyleGate` checks the text each `gh pr|issue create|edit|comment` in a bash command sends
9
+ * (see gh-command.ts) and decides whether the extension blocks the call (once), adds a note, or lets
10
+ * it pass.
11
+ */
12
+ import { createHash } from "node:crypto";
13
+ import type { GitHubStyleMode } from "./config.ts";
14
+ import { extractGhTexts, type GhText, type GhTextKind } from "./gh-command.ts";
15
+
16
+ export type { GhText } from "./gh-command.ts";
17
+
18
+ /** Visible words allowed, by kind. Code, URLs, HTML comments, tables, headings and <details> blocks do not count. */
19
+ export const WORD_LIMITS: Readonly<Record<GhTextKind, number>> = { pr: 250, issue: 250, comment: 150 };
20
+ /** Text longer than this is reported as too long and not checked further, so the check stays fast. */
21
+ export const MAX_LINT_CHARS = 100_000;
22
+
23
+ export const MAX_SENTENCE_WORDS = 25;
24
+ export const MAX_LIST_ITEMS = 5;
25
+ /** Matches the "<70 chars" title rule of the /pr skill. */
26
+ export const MAX_TITLE_CHARS = 69;
27
+ /** Blocked commands remembered for the block-once rule; the oldest is forgotten first. */
28
+ export const MAX_REMEMBERED_BLOCKS = 200;
29
+
30
+ export const FILLER_TERMS = [
31
+ "simply",
32
+ "seamless",
33
+ "seamlessly",
34
+ "robust",
35
+ "powerful",
36
+ "comprehensive",
37
+ "leverage",
38
+ "leverages",
39
+ "leveraged",
40
+ "leveraging",
41
+ "crucial",
42
+ "delve",
43
+ "in order to",
44
+ "it is worth noting",
45
+ ] as const;
46
+
47
+ const EXAMPLE_SENTENCE_CHARS = 60;
48
+ const EXAMPLE_BOLD_CHARS = 30;
49
+ const MAX_BOLD_EXAMPLES = 3;
50
+ const TAB_WIDTH = 4;
51
+
52
+ export const GITHUB_STYLE_GUIDE = [
53
+ "GitHub text style (pull request and issue titles, bodies, comments). Readers skim, so:",
54
+ `- Title: at most ${MAX_TITLE_CHARS} characters, imperative ("Add rate limit to /login").`,
55
+ "- First line of the body: one sentence that says what changes and why (issue: what is wrong and its effect).",
56
+ `- Then short sections: Summary (at most 3 bullets), Test plan or Acceptance criteria. No more than ${MAX_LIST_ITEMS} items in a list or sub-list.`,
57
+ `- Plain English: at most ${MAX_SENTENCE_WORDS} words per sentence, active voice, simple tenses, one term for one thing. Use can/will/must, not should/may/might.`,
58
+ `- No em-dashes, no bold, no emoji, no filler (${FILLER_TERMS.join(", ")}). State the fact, not its importance.`,
59
+ "- End with one next step for the reader, for example \"Review: start at `src/auth.ts:42`.\"",
60
+ `- Keep the visible text at ${WORD_LIMITS.pr} words or fewer (comments: ${WORD_LIMITS.comment}). Code, URLs, HTML comments, tables, headings and <details> blocks do not count. Put long required content (evidence bundles, decisions, logs) at the end in one <details><summary>…</summary> block.`,
61
+ "- Keep every heading, section and marker that a skill template requires: shorten its content or move it into <details>, never drop or rename it.",
62
+ "- Never change code, identifiers, commands, paths, error text or numbers to fit these rules.",
63
+ ].join("\n");
64
+
65
+ /** The rules for the system prompt, or undefined when the style is off. */
66
+ export function styleGuideFor(mode: GitHubStyleMode): string | undefined {
67
+ return mode === "off" ? undefined : GITHUB_STYLE_GUIDE;
68
+ }
69
+
70
+ // ---------------------------------------------------------------- lint
71
+
72
+ /**
73
+ * Marks where a block (code, table, <details>, comment) was removed, so the lists and paragraphs on
74
+ * either side stay apart. A blank line cannot do this: list items may have blank lines between them.
75
+ * The break keeps the block's indentation, so a block inside a list item stays part of that item.
76
+ */
77
+ const BLOCK_BREAK = "\u0000";
78
+
79
+ const isSpaceOrTab = (char: string | undefined) => char === " " || char === "\t";
80
+
81
+ /**
82
+ * Remove every `open ... close` span (case-insensitive), in one pass. A span alone on its lines
83
+ * becomes a block break; a span inside a line becomes a space. An unclosed span runs to the end.
84
+ */
85
+ function removeSpans(text: string, open: string, close: string): string {
86
+ const lower = text.toLowerCase();
87
+ let out = "";
88
+ let i = 0;
89
+ while (i < text.length) {
90
+ const openAt = lower.indexOf(open, i);
91
+ if (openAt < 0) break;
92
+ const closeAt = lower.indexOf(close, openAt + open.length);
93
+ const spanEnd = closeAt < 0 ? text.length : closeAt + close.length;
94
+ let lineStart = openAt;
95
+ while (isSpaceOrTab(text[lineStart - 1])) lineStart--;
96
+ let lineEnd = spanEnd;
97
+ while (isSpaceOrTab(text[lineEnd])) lineEnd++;
98
+ const aloneOnLine = (lineStart === 0 || text[lineStart - 1] === "\n") && (lineEnd === text.length || text[lineEnd] === "\n");
99
+ out += text.slice(i, openAt) + (aloneOnLine ? BLOCK_BREAK : " ");
100
+ i = spanEnd;
101
+ }
102
+ return out + text.slice(i);
103
+ }
104
+
105
+ const FENCE = /^[ \t]*(`{3,}|~{3,})/;
106
+ const TABLE_ROW = /^[ \t]*\|/;
107
+ const HEADING = /^[ \t]*#{1,6}(?:[ \t]|$)/;
108
+ const LIST_MARKER = /^([ \t]*)(?:[-*+]|\d+[.)])[ \t]+(?:\[[ xX]\][ \t]+)?/;
109
+
110
+ /** The body as the reader first sees it: no code, URLs, collapsed details, HTML comments or tables. */
111
+ export function visibleText(body: string): string {
112
+ return visibleWithBreaks(body).replaceAll(BLOCK_BREAK, "");
113
+ }
114
+
115
+ /** visibleText, with a BLOCK_BREAK line where each block was removed. */
116
+ function visibleWithBreaks(body: string): string {
117
+ // Code goes first, so a `<details>` or `<!--` quoted in code is not taken for HTML.
118
+ const withoutCode = removeFencedCode(body.replace(/\r\n?/g, "\n")).replace(/`[^`\n]*`/g, "");
119
+ return removeSpans(removeSpans(withoutCode, "<!--", "-->"), "<details", "</details>")
120
+ .split("\n")
121
+ .map((line) => (TABLE_ROW.test(line) ? indentOf(line) + BLOCK_BREAK : line))
122
+ .join("\n")
123
+ .replace(/https?:\/\/\S+/g, "");
124
+ }
125
+
126
+ /** Each line of a fenced block becomes a block break with the opening fence's indentation, blank lines included. */
127
+ function removeFencedCode(text: string): string {
128
+ let fence: { marker: string; indent: string } | undefined;
129
+ return text
130
+ .split("\n")
131
+ .map((line) => {
132
+ const marker = FENCE.exec(line)?.[1];
133
+ if (fence) {
134
+ const indent = fence.indent;
135
+ if (marker && marker[0] === fence.marker[0] && marker.length >= fence.marker.length) fence = undefined;
136
+ return indent + BLOCK_BREAK;
137
+ }
138
+ if (!marker) return line;
139
+ fence = { marker, indent: indentOf(line) };
140
+ return fence.indent + BLOCK_BREAK;
141
+ })
142
+ .join("\n");
143
+ }
144
+
145
+ function indentOf(line: string): string {
146
+ return /^[ \t]*/.exec(line)?.[0] ?? "";
147
+ }
148
+
149
+ /** Indentation width in columns, a tab counting as TAB_WIDTH. */
150
+ function indentWidth(indent: string): number {
151
+ return indent.replace(/\t/g, " ".repeat(TAB_WIDTH)).length;
152
+ }
153
+
154
+ function splitWords(text: string): string[] {
155
+ return text.match(/[A-Za-z0-9][\w'’./#:-]*/g) ?? [];
156
+ }
157
+
158
+ function clip(text: string, maxChars = EXAMPLE_SENTENCE_CHARS): string {
159
+ const collapsed = text.trim().replace(/\s+/g, " ");
160
+ return collapsed.length > maxChars ? `${collapsed.slice(0, maxChars)}…` : collapsed;
161
+ }
162
+
163
+ /** Paragraphs and list items, each joined onto one line, so a hard-wrapped sentence is measured whole. */
164
+ function textBlocks(visible: string): string[] {
165
+ const blocks: string[] = [];
166
+ let blockLines: string[] = [];
167
+ const flush = () => {
168
+ if (blockLines.length) blocks.push(blockLines.join(" "));
169
+ blockLines = [];
170
+ };
171
+ for (const line of visible.split("\n")) {
172
+ if (!line.trim() || line.trim() === BLOCK_BREAK || HEADING.test(line)) {
173
+ flush();
174
+ continue;
175
+ }
176
+ const item = LIST_MARKER.exec(line);
177
+ if (item) flush();
178
+ blockLines.push(item ? line.slice(item[0].length) : line.trim());
179
+ }
180
+ flush();
181
+ return blocks;
182
+ }
183
+
184
+ /** Items of the longest list. A sub-list is a list of its own; its items do not count for the parent. */
185
+ function longestListRun(visible: string): number {
186
+ let longest = 0;
187
+ const open: { indent: number; items: number }[] = [];
188
+ for (const line of visible.split("\n")) {
189
+ const item = LIST_MARKER.exec(line);
190
+ if (item) {
191
+ const indent = indentWidth(item[1]);
192
+ while (open.length && open[open.length - 1].indent > indent) open.pop();
193
+ const top = open[open.length - 1];
194
+ if (top?.indent === indent) top.items++;
195
+ else open.push({ indent, items: 1 });
196
+ longest = Math.max(longest, open[open.length - 1].items);
197
+ } else if (line.trim() && indentWidth(indentOf(line)) < 2) open.length = 0;
198
+ }
199
+ return longest;
200
+ }
201
+
202
+ const HEDGES = /\b(?:should|might|may)\b/gi;
203
+ const FILLER = new RegExp(`\\b(?:${FILLER_TERMS.join("|")})\\b`, "gi");
204
+
205
+ type LintRule = (text: GhText, visible: string) => string | undefined;
206
+
207
+ const uniqueLowercased = (matches: string[]) => [...new Set(matches.map((m) => m.toLowerCase()))];
208
+
209
+ /** Hedge words in any case, except "May" as a month ("May 2026"). */
210
+ function findHedges(visible: string): string[] {
211
+ const monthAfterMatch = /[ \t]+\d/y;
212
+ const isMonth = (m: RegExpExecArray) => {
213
+ monthAfterMatch.lastIndex = m.index + m[0].length;
214
+ return m[0] === "May" && monthAfterMatch.test(visible);
215
+ };
216
+ return [...visible.matchAll(HEDGES)].filter((m) => !isMonth(m)).map((m) => m[0]);
217
+ }
218
+
219
+ const LINT_RULES: LintRule[] = [
220
+ ({ title }) =>
221
+ title !== undefined && title.length > MAX_TITLE_CHARS
222
+ ? `Title has ${title.length} characters. Keep it at ${MAX_TITLE_CHARS} or fewer.`
223
+ : undefined,
224
+ ({ kind }, visible) => {
225
+ const limit = WORD_LIMITS[kind];
226
+ const count = splitWords(visible.split("\n").filter((l) => !HEADING.test(l)).join("\n")).length;
227
+ return count > limit
228
+ ? `Body has ${count} visible words. Keep it at ${limit} or fewer: cut, or move long required content into one <details> block at the end.`
229
+ : undefined;
230
+ },
231
+ (_, visible) => (visible.includes("—") ? "Remove the em-dashes (—). Write two sentences or name the relation (because, but)." : undefined),
232
+ (_, visible) => {
233
+ const spans = visible.match(/\*\*[^*\n]+\*\*/g);
234
+ return spans ? `Remove the bold (${spans.slice(0, MAX_BOLD_EXAMPLES).map((b) => clip(b, EXAMPLE_BOLD_CHARS)).join(", ")}).` : undefined;
235
+ },
236
+ (_, visible) => {
237
+ const hedges = uniqueLowercased(findHedges(visible));
238
+ return hedges.length ? `Replace ${hedges.map((h) => `"${h}"`).join(", ")} with can, will or must, or delete it.` : undefined;
239
+ },
240
+ (_, visible) => {
241
+ const filler = uniqueLowercased(visible.match(FILLER) ?? []);
242
+ return filler.length ? `Delete the filler words: ${filler.map((f) => `"${f}"`).join(", ")}.` : undefined;
243
+ },
244
+ (_, visible) => {
245
+ const longSentences = textBlocks(visible)
246
+ .flatMap((block) => block.split(/(?<=[.!?])\s+/))
247
+ .filter((sentence) => splitWords(sentence).length > MAX_SENTENCE_WORDS);
248
+ return longSentences.length
249
+ ? `Split ${longSentences.length} sentence(s) over ${MAX_SENTENCE_WORDS} words, for example: "${clip(longSentences[0])}"`
250
+ : undefined;
251
+ },
252
+ (_, visible) => {
253
+ const items = longestListRun(visible);
254
+ return items > MAX_LIST_ITEMS
255
+ ? `A list has ${items} items. Keep at most ${MAX_LIST_ITEMS}: group them, or move the rest into a <details> block.`
256
+ : undefined;
257
+ },
258
+ ];
259
+
260
+ /** Breaks of the mechanical rules in GITHUB_STYLE_GUIDE. Empty when the text passes. */
261
+ export function lintGhText(ghText: GhText): string[] {
262
+ if (ghText.bodyFileTooLarge || (ghText.body !== undefined && ghText.body.length > MAX_LINT_CHARS)) {
263
+ return [`The body is longer than ${MAX_LINT_CHARS} characters. Cut it, or link to a file in the repository.`];
264
+ }
265
+ const visible = ghText.body === undefined ? "" : visibleWithBreaks(ghText.body);
266
+ return LINT_RULES.map((rule) => rule(ghText, visible)).filter((p): p is string => p !== undefined);
267
+ }
268
+
269
+ export function styleFeedback(problems: string[]): string {
270
+ return [
271
+ "dev-team GitHub style: rewrite the text before you send it (see \"GitHub text style\" in the system prompt).",
272
+ ...problems.map((p) => `- ${p}`),
273
+ "Keep code, identifiers, commands, paths, error text, numbers and required template sections exactly as they are. If a rule cannot apply, send the same command with the same text again: the second identical call is not blocked.",
274
+ ].join("\n");
275
+ }
276
+
277
+ // ---------------------------------------------------------------- gate
278
+
279
+ export interface StyleVerdict {
280
+ /** Reason to block the call. */
281
+ block?: string;
282
+ /** Advisory for the model; the call runs. */
283
+ note?: string;
284
+ }
285
+
286
+ /**
287
+ * The block-once policy. In "block" mode a command whose text breaks the rules is blocked the first
288
+ * time and passes when sent again with the same text, so a rule that cannot apply never traps the
289
+ * agent. The key is the command and the text it sends, so an edited body file is checked again. The
290
+ * gate remembers blocked keys by hash, at most `maxRememberedBlocks`, oldest forgotten first.
291
+ */
292
+ export function createStyleGate(maxRememberedBlocks = MAX_REMEMBERED_BLOCKS): (mode: GitHubStyleMode, command: string, cwd: string) => StyleVerdict {
293
+ const blockedCommandHashes = new Set<string>();
294
+ return (mode, command, cwd) => {
295
+ if (mode === "off") return {};
296
+ const ghTexts = extractGhTexts(command, cwd);
297
+ const problems = ghTexts.flatMap(lintGhText);
298
+ if (!problems.length) return {};
299
+ const feedback = styleFeedback(problems);
300
+ if (mode === "warn") return { note: feedback };
301
+ const key = createHash("sha256").update(JSON.stringify([command, ghTexts])).digest("hex");
302
+ if (blockedCommandHashes.has(key)) return {};
303
+ blockedCommandHashes.add(key);
304
+ if (blockedCommandHashes.size > maxRememberedBlocks) blockedCommandHashes.delete(blockedCommandHashes.values().next().value as string);
305
+ return { block: feedback };
306
+ };
307
+ }