@huicai/cli 2026.814.0 → 2026.1021.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 (493) hide show
  1. package/LICENSE +391 -32
  2. package/README.md +139 -8
  3. package/bin/huicai.js +155 -74
  4. package/bin/update.js +97 -0
  5. package/package.json +27 -8
  6. package/skills/ab-testing/trigger-cases.json +30 -0
  7. package/skills/academic-writing/trigger-cases.json +30 -0
  8. package/skills/accounting-ops/trigger-cases.json +30 -0
  9. package/skills/ai-agent/trigger-cases.json +30 -0
  10. package/skills/ai-aiops/trigger-cases.json +30 -0
  11. package/skills/ai-coding/SKILL.md +2 -0
  12. package/skills/ai-coding/trigger-cases.json +30 -0
  13. package/skills/ai-compliance/trigger-cases.json +30 -0
  14. package/skills/ai-eval/trigger-cases.json +30 -0
  15. package/skills/ai-llm-app/trigger-cases.json +30 -0
  16. package/skills/ai-mlops/trigger-cases.json +30 -0
  17. package/skills/ai-multimodal/trigger-cases.json +30 -0
  18. package/skills/ai-prompt/trigger-cases.json +30 -0
  19. package/skills/ai-rag/trigger-cases.json +30 -0
  20. package/skills/anomaly-detection/trigger-cases.json +30 -0
  21. package/skills/api-design/trigger-cases.json +31 -0
  22. package/skills/api-integration/trigger-cases.json +31 -0
  23. package/skills/arch-design/trigger-cases.json +12 -0
  24. package/skills/arch-diagram/SKILL.md +118 -0
  25. package/skills/arch-diagram/trigger-cases.json +30 -0
  26. package/skills/arch-distributed/trigger-cases.json +30 -0
  27. package/skills/arch-multitenant/trigger-cases.json +30 -0
  28. package/skills/audio-brief/SKILL.md +65 -0
  29. package/skills/audio-brief/trigger-cases.json +30 -0
  30. package/skills/audit-assist/trigger-cases.json +30 -0
  31. package/skills/audit-chain/trigger-cases.json +31 -0
  32. package/skills/banking-credit/trigger-cases.json +30 -0
  33. package/skills/brand-design/trigger-cases.json +30 -0
  34. package/skills/business-plan/trigger-cases.json +30 -0
  35. package/skills/capital-ops/trigger-cases.json +30 -0
  36. package/skills/cicd-pipeline/trigger-cases.json +31 -0
  37. package/skills/code-archaeology/SKILL.md +55 -0
  38. package/skills/code-archaeology/trigger-cases.json +9 -0
  39. package/skills/code-quality/SKILL.md +138 -0
  40. package/skills/code-quality/references/languages.md +107 -0
  41. package/skills/code-quality/scripts/__pycache__/code_battery.cpython-312.pyc +0 -0
  42. package/skills/code-quality/scripts/__pycache__/code_check.cpython-312.pyc +0 -0
  43. package/skills/code-quality/scripts/__pycache__/code_check.cpython-313.pyc +0 -0
  44. package/skills/code-quality/scripts/__pycache__/code_csharp.cpython-312.pyc +0 -0
  45. package/skills/code-quality/scripts/__pycache__/code_csharp.cpython-313.pyc +0 -0
  46. package/skills/code-quality/scripts/__pycache__/code_fix.cpython-312.pyc +0 -0
  47. package/skills/code-quality/scripts/__pycache__/code_fix.cpython-313.pyc +0 -0
  48. package/skills/code-quality/scripts/__pycache__/code_java.cpython-312.pyc +0 -0
  49. package/skills/code-quality/scripts/__pycache__/code_java.cpython-313.pyc +0 -0
  50. package/skills/code-quality/scripts/__pycache__/code_jsts.cpython-312.pyc +0 -0
  51. package/skills/code-quality/scripts/__pycache__/code_jsts.cpython-313.pyc +0 -0
  52. package/skills/code-quality/scripts/__pycache__/code_lens.cpython-312.pyc +0 -0
  53. package/skills/code-quality/scripts/__pycache__/code_lens.cpython-313.pyc +0 -0
  54. package/skills/code-quality/scripts/__pycache__/code_python.cpython-312.pyc +0 -0
  55. package/skills/code-quality/scripts/__pycache__/code_python.cpython-313.pyc +0 -0
  56. package/skills/code-quality/scripts/__pycache__/code_testplan.cpython-312.pyc +0 -0
  57. package/skills/code-quality/scripts/code_battery.py +1072 -0
  58. package/skills/code-quality/scripts/code_check.py +1269 -0
  59. package/skills/code-quality/scripts/code_csharp.py +371 -0
  60. package/skills/code-quality/scripts/code_fix.py +201 -0
  61. package/skills/code-quality/scripts/code_java.py +695 -0
  62. package/skills/code-quality/scripts/code_jsts.py +313 -0
  63. package/skills/code-quality/scripts/code_lens.py +1079 -0
  64. package/skills/code-quality/scripts/code_python.py +536 -0
  65. package/skills/code-quality/scripts/code_testplan.py +239 -0
  66. package/skills/code-quality/trigger-cases.json +45 -0
  67. package/skills/code-review/SKILL.md +24 -0
  68. package/skills/code-review/trigger-cases.json +35 -0
  69. package/skills/commit-and-pr/trigger-cases.json +31 -0
  70. package/skills/content-creation/trigger-cases.json +30 -0
  71. package/skills/corporate-governance/trigger-cases.json +30 -0
  72. package/skills/crawl-chain/trigger-cases.json +31 -0
  73. package/skills/customer-service/trigger-cases.json +30 -0
  74. package/skills/data-analysis/trigger-cases.json +30 -0
  75. package/skills/data-chain/SKILL.md +1 -1
  76. package/skills/data-chain/trigger-cases.json +31 -0
  77. package/skills/data-governance/trigger-cases.json +30 -0
  78. package/skills/data-report-pro/trigger-cases.json +30 -0
  79. package/skills/data-streaming/trigger-cases.json +30 -0
  80. package/skills/data-wrangling/SKILL.md +1 -1
  81. package/skills/data-wrangling/trigger-cases.json +30 -0
  82. package/skills/db-es/trigger-cases.json +30 -0
  83. package/skills/db-migration/trigger-cases.json +30 -0
  84. package/skills/db-mysql/trigger-cases.json +30 -0
  85. package/skills/db-postgres/trigger-cases.json +30 -0
  86. package/skills/db-redis/trigger-cases.json +30 -0
  87. package/skills/debug-root-cause/trigger-cases.json +30 -0
  88. package/skills/dependency-audit/SKILL.md +56 -0
  89. package/skills/dependency-audit/trigger-cases.json +7 -0
  90. package/skills/dependency-upgrade/trigger-cases.json +31 -0
  91. package/skills/dev-cpp/trigger-cases.json +30 -0
  92. package/skills/dev-cross-platform/trigger-cases.json +30 -0
  93. package/skills/dev-csharp/SKILL.md +23 -0
  94. package/skills/dev-csharp/trigger-cases.json +30 -0
  95. package/skills/dev-frontend/SKILL.md +19 -0
  96. package/skills/dev-frontend/trigger-cases.json +30 -0
  97. package/skills/dev-go/trigger-cases.json +30 -0
  98. package/skills/dev-harmony/trigger-cases.json +30 -0
  99. package/skills/dev-java/SKILL.md +20 -0
  100. package/skills/dev-java/trigger-cases.json +30 -0
  101. package/skills/dev-mobile/trigger-cases.json +30 -0
  102. package/skills/dev-node/trigger-cases.json +30 -0
  103. package/skills/dev-php/trigger-cases.json +30 -0
  104. package/skills/dev-python/SKILL.md +21 -0
  105. package/skills/dev-python/trigger-cases.json +30 -0
  106. package/skills/dev-rust/trigger-cases.json +30 -0
  107. package/skills/dev-toolchain/trigger-cases.json +31 -0
  108. package/skills/doc-chain/trigger-cases.json +31 -0
  109. package/skills/doc-compare/trigger-cases.json +30 -0
  110. package/skills/docx-author/SKILL.md +127 -25
  111. package/skills/docx-author/scripts/__pycache__/docx_battery.cpython-312.pyc +0 -0
  112. package/skills/docx-author/scripts/__pycache__/docx_build.cpython-312.pyc +0 -0
  113. package/skills/docx-author/scripts/__pycache__/docx_check.cpython-312.pyc +0 -0
  114. package/skills/docx-author/scripts/__pycache__/docx_layout.cpython-312.pyc +0 -0
  115. package/skills/docx-author/scripts/__pycache__/zh_prose.cpython-312.pyc +0 -0
  116. package/skills/docx-author/scripts/docx_battery.py +586 -0
  117. package/skills/docx-author/scripts/docx_build.py +995 -0
  118. package/skills/docx-author/scripts/docx_check.py +1306 -0
  119. package/skills/docx-author/scripts/docx_doc.py +14 -154
  120. package/skills/docx-author/scripts/docx_layout.py +490 -0
  121. package/skills/docx-author/scripts/zh_prose.py +639 -0
  122. package/skills/docx-author/trigger-cases.json +58 -0
  123. package/skills/echo-brief/SKILL.md +84 -0
  124. package/skills/echo-brief/references/echo-format.md +68 -0
  125. package/skills/echo-brief/trigger-cases.json +40 -0
  126. package/skills/ecommerce-ops/trigger-cases.json +30 -0
  127. package/skills/education-training/trigger-cases.json +30 -0
  128. package/skills/ehs-safety/trigger-cases.json +30 -0
  129. package/skills/email-writing/trigger-cases.json +30 -0
  130. package/skills/eng-ai/trigger-cases.json +30 -0
  131. package/skills/eng-architecture/trigger-cases.json +31 -0
  132. package/skills/eng-automation/trigger-cases.json +31 -0
  133. package/skills/eng-collaboration/trigger-cases.json +30 -0
  134. package/skills/eng-complex-env/trigger-cases.json +30 -0
  135. package/skills/eng-data-platform/trigger-cases.json +31 -0
  136. package/skills/eng-database/trigger-cases.json +31 -0
  137. package/skills/eng-develop/SKILL.md +9 -1
  138. package/skills/eng-develop/references/dod-checklist.md +3 -0
  139. package/skills/eng-develop/references/engineering-workflow.md +37 -0
  140. package/skills/eng-develop/trigger-cases.json +30 -0
  141. package/skills/eng-docs/SKILL.md +24 -0
  142. package/skills/eng-docs/trigger-cases.json +30 -0
  143. package/skills/eng-efficiency/trigger-cases.json +30 -0
  144. package/skills/eng-infra/trigger-cases.json +30 -0
  145. package/skills/eng-integration/trigger-cases.json +31 -0
  146. package/skills/eng-legacy/trigger-cases.json +31 -0
  147. package/skills/eng-observability/trigger-cases.json +31 -0
  148. package/skills/eng-ops/trigger-cases.json +31 -0
  149. package/skills/eng-performance/trigger-cases.json +31 -0
  150. package/skills/eng-planning/trigger-cases.json +31 -0
  151. package/skills/eng-quality/SKILL.md +8 -0
  152. package/skills/eng-quality/trigger-cases.json +31 -0
  153. package/skills/eng-release/trigger-cases.json +31 -0
  154. package/skills/eng-reliability/trigger-cases.json +31 -0
  155. package/skills/eng-requirements/trigger-cases.json +12 -0
  156. package/skills/eng-research/trigger-cases.json +30 -0
  157. package/skills/eng-security/trigger-cases.json +31 -0
  158. package/skills/eng-ux/trigger-cases.json +30 -0
  159. package/skills/engineering-chain/trigger-cases.json +30 -0
  160. package/skills/env-offline/trigger-cases.json +31 -0
  161. package/skills/env-private-deploy/trigger-cases.json +31 -0
  162. package/skills/env-xinchuang/trigger-cases.json +31 -0
  163. package/skills/equipment-tpm/trigger-cases.json +30 -0
  164. package/skills/esg-report/trigger-cases.json +30 -0
  165. package/skills/event-management/trigger-cases.json +30 -0
  166. package/skills/excel-analysis-chain/SKILL.md +17 -4
  167. package/skills/excel-analysis-chain/trigger-cases.json +31 -0
  168. package/skills/explain-codebase/trigger-cases.json +11 -0
  169. package/skills/file-ingest/trigger-cases.json +30 -0
  170. package/skills/finance-analysis/trigger-cases.json +31 -0
  171. package/skills/finance-chain/trigger-cases.json +31 -0
  172. package/skills/financial-modeling/trigger-cases.json +31 -0
  173. package/skills/find-simplifications/SKILL.md +43 -0
  174. package/skills/find-simplifications/trigger-cases.json +23 -0
  175. package/skills/foreign-trade/trigger-cases.json +30 -0
  176. package/skills/funnel-cohort/trigger-cases.json +30 -0
  177. package/skills/gov-document/trigger-cases.json +30 -0
  178. package/skills/gui-change-evidence/SKILL.md +47 -0
  179. package/skills/gui-change-evidence/trigger-cases.json +23 -0
  180. package/skills/hr-chain/trigger-cases.json +31 -0
  181. package/skills/hr-operations/trigger-cases.json +30 -0
  182. package/skills/info-disclosure/trigger-cases.json +31 -0
  183. package/skills/infra-gateway/trigger-cases.json +31 -0
  184. package/skills/infra-k8s/trigger-cases.json +31 -0
  185. package/skills/infra-mq/trigger-cases.json +30 -0
  186. package/skills/insurance-advisory/trigger-cases.json +30 -0
  187. package/skills/internal-audit/trigger-cases.json +30 -0
  188. package/skills/ip-management/trigger-cases.json +31 -0
  189. package/skills/ipo-listing/trigger-cases.json +31 -0
  190. package/skills/it-audit/trigger-cases.json +31 -0
  191. package/skills/itsm-ops/trigger-cases.json +31 -0
  192. package/skills/knowledge-sop/trigger-cases.json +31 -0
  193. package/skills/legal-chain/trigger-cases.json +31 -0
  194. package/skills/legal-contract/trigger-cases.json +30 -0
  195. package/skills/litigation-support/trigger-cases.json +31 -0
  196. package/skills/logistics-warehouse/trigger-cases.json +30 -0
  197. package/skills/long-doc-analysis/trigger-cases.json +31 -0
  198. package/skills/management-accounting/trigger-cases.json +30 -0
  199. package/skills/manufacturing-chain/trigger-cases.json +31 -0
  200. package/skills/manufacturing-quality/trigger-cases.json +30 -0
  201. package/skills/marketing-analytics/trigger-cases.json +31 -0
  202. package/skills/marketing-chain/trigger-cases.json +31 -0
  203. package/skills/meeting-minutes/trigger-cases.json +30 -0
  204. package/skills/metrics-system/trigger-cases.json +31 -0
  205. package/skills/negotiation-prep/trigger-cases.json +30 -0
  206. package/skills/obs-prometheus/trigger-cases.json +31 -0
  207. package/skills/office-automation/trigger-cases.json +31 -0
  208. package/skills/okr-review/trigger-cases.json +30 -0
  209. package/skills/ops-fleet/trigger-cases.json +31 -0
  210. package/skills/ops-linux/trigger-cases.json +31 -0
  211. package/skills/optimization-solver/trigger-cases.json +30 -0
  212. package/skills/patent-disclosure/SKILL.md +105 -0
  213. package/skills/patent-disclosure/references/figures.md +110 -0
  214. package/skills/patent-disclosure/references/outline.md +162 -0
  215. package/skills/patent-disclosure/scripts/patent_docx.py +230 -0
  216. package/skills/patent-disclosure/trigger-cases.json +31 -0
  217. package/skills/patent-drafting/SKILL.md +108 -0
  218. package/skills/patent-drafting/trigger-cases.json +31 -0
  219. package/skills/patent-portfolio/SKILL.md +81 -0
  220. package/skills/patent-portfolio/trigger-cases.json +31 -0
  221. package/skills/pdf-toolkit/trigger-cases.json +31 -0
  222. package/skills/perf-optimize/trigger-cases.json +31 -0
  223. package/skills/pivot-crosstab/trigger-cases.json +30 -0
  224. package/skills/policy-analysis/trigger-cases.json +31 -0
  225. package/skills/portfolio-analysis/trigger-cases.json +31 -0
  226. package/skills/ppt-chain/SKILL.md +14 -6
  227. package/skills/ppt-chain/trigger-cases.json +31 -0
  228. package/skills/pptx-author/SKILL.md +86 -33
  229. package/skills/pptx-author/scripts/__pycache__/pptx_check.cpython-312.pyc +0 -0
  230. package/skills/pptx-author/scripts/__pycache__/pptx_deck.cpython-312.pyc +0 -0
  231. package/skills/pptx-author/scripts/__pycache__/pptx_layout.cpython-312.pyc +0 -0
  232. package/skills/pptx-author/scripts/pptx_battery.py +178 -0
  233. package/skills/pptx-author/scripts/pptx_build.py +119 -0
  234. package/skills/pptx-author/scripts/pptx_check.py +1182 -0
  235. package/skills/pptx-author/scripts/pptx_deck.py +736 -145
  236. package/skills/pptx-author/scripts/pptx_layout.py +384 -0
  237. package/skills/pptx-author/trigger-cases.json +15 -0
  238. package/skills/pr-comms/trigger-cases.json +30 -0
  239. package/skills/procurement-supply/trigger-cases.json +31 -0
  240. package/skills/product-design/trigger-cases.json +31 -0
  241. package/skills/production-planning/trigger-cases.json +31 -0
  242. package/skills/project-management/trigger-cases.json +31 -0
  243. package/skills/project-proposal/trigger-cases.json +31 -0
  244. package/skills/prose-standard/SKILL.md +53 -0
  245. package/skills/prose-standard/trigger-cases.json +23 -0
  246. package/skills/qa-api-automation/trigger-cases.json +31 -0
  247. package/skills/qa-mobile-automation/trigger-cases.json +31 -0
  248. package/skills/qa-ui-automation/trigger-cases.json +31 -0
  249. package/skills/quant-analysis/trigger-cases.json +31 -0
  250. package/skills/rag-triage/SKILL.md +64 -0
  251. package/skills/rag-triage/evals.json +57 -0
  252. package/skills/rag-triage/references/triage-playbook.md +75 -0
  253. package/skills/rag-triage/trigger-cases.json +31 -0
  254. package/skills/real-estate-property/trigger-cases.json +30 -0
  255. package/skills/refactor-safely/SKILL.md +1 -1
  256. package/skills/refactor-safely/trigger-cases.json +30 -0
  257. package/skills/regression-forecast/trigger-cases.json +31 -0
  258. package/skills/release-checklist/trigger-cases.json +31 -0
  259. package/skills/report-craft/SKILL.md +76 -0
  260. package/skills/report-craft/references/feasibility.md +118 -0
  261. package/skills/report-craft/references/review-checklist.md +51 -0
  262. package/skills/report-craft/references/visuals.md +114 -0
  263. package/skills/report-craft/references/writing.md +80 -0
  264. package/skills/report-craft/scripts/__pycache__/chart_render.cpython-312.pyc +0 -0
  265. package/skills/report-craft/scripts/__pycache__/fin_model.cpython-312.pyc +0 -0
  266. package/skills/report-craft/scripts/__pycache__/project_facts.cpython-312.pyc +0 -0
  267. package/skills/report-craft/scripts/chart_render.py +1222 -0
  268. package/skills/report-craft/scripts/fin_model.py +602 -0
  269. package/skills/report-craft/scripts/project_facts.py +580 -0
  270. package/skills/report-craft/scripts/report_battery.py +349 -0
  271. package/skills/report-craft/trigger-cases.json +15 -0
  272. package/skills/retail-store-ops/trigger-cases.json +30 -0
  273. package/skills/risk-compliance/trigger-cases.json +31 -0
  274. package/skills/scope-creep/SKILL.md +45 -0
  275. package/skills/scope-creep/trigger-cases.json +7 -0
  276. package/skills/sec-auth/trigger-cases.json +31 -0
  277. package/skills/sec-compliance/trigger-cases.json +31 -0
  278. package/skills/securities-chain/trigger-cases.json +31 -0
  279. package/skills/securities-research/trigger-cases.json +31 -0
  280. package/skills/security-audit/trigger-cases.json +31 -0
  281. package/skills/slides-html/SKILL.md +25 -10
  282. package/skills/slides-html/trigger-cases.json +11 -0
  283. package/skills/sql-analysis/SKILL.md +110 -0
  284. package/skills/sql-analysis/trigger-cases.json +34 -0
  285. package/skills/sql-tuning/trigger-cases.json +31 -0
  286. package/skills/statistical-testing/trigger-cases.json +31 -0
  287. package/skills/strategy-planning/trigger-cases.json +30 -0
  288. package/skills/supply-chain/trigger-cases.json +31 -0
  289. package/skills/tax-compliance/trigger-cases.json +30 -0
  290. package/skills/tech-doc/SKILL.md +262 -0
  291. package/skills/tech-doc/scripts/__pycache__/archive_battery.cpython-312.pyc +0 -0
  292. package/skills/tech-doc/scripts/__pycache__/archive_build.cpython-312.pyc +0 -0
  293. package/skills/tech-doc/scripts/__pycache__/archive_check.cpython-312.pyc +0 -0
  294. package/skills/tech-doc/scripts/__pycache__/archive_spec.cpython-312.pyc +0 -0
  295. package/skills/tech-doc/scripts/__pycache__/doc_templates.cpython-312.pyc +0 -0
  296. package/skills/tech-doc/scripts/archive_battery.py +860 -0
  297. package/skills/tech-doc/scripts/archive_build.py +599 -0
  298. package/skills/tech-doc/scripts/archive_check.py +1307 -0
  299. package/skills/tech-doc/scripts/archive_spec.py +499 -0
  300. package/skills/tech-doc/scripts/doc_templates.py +624 -0
  301. package/skills/tech-doc/trigger-cases.json +57 -0
  302. package/skills/tech-research/trigger-cases.json +31 -0
  303. package/skills/tender-bidding/trigger-cases.json +31 -0
  304. package/skills/translation-pro/trigger-cases.json +30 -0
  305. package/skills/treasury-mgmt/trigger-cases.json +31 -0
  306. package/skills/trim-cot-leakage/SKILL.md +58 -0
  307. package/skills/trim-cot-leakage/trigger-cases.json +23 -0
  308. package/skills/web-craft/SKILL.md +103 -0
  309. package/skills/web-craft/references/craft-checklist.md +75 -0
  310. package/skills/web-craft/references/design-direction.md +122 -0
  311. package/skills/web-craft/references/h5-mobile.md +100 -0
  312. package/skills/web-craft/references/motion.md +136 -0
  313. package/skills/web-craft/references/recipes.md +74 -0
  314. package/skills/web-craft/templates/wedding-invitation.html +1180 -0
  315. package/skills/web-craft/trigger-cases.json +14 -0
  316. package/skills/web-scraping/trigger-cases.json +34 -0
  317. package/skills/web-search/SKILL.md +11 -10
  318. package/skills/web-search/trigger-cases.json +31 -0
  319. package/skills/weekly-report/SKILL.md +134 -0
  320. package/skills/weekly-report/trigger-cases.json +11 -0
  321. package/skills/write-tests/trigger-cases.json +31 -0
  322. package/skills/xlsx-analysis/SKILL.md +143 -77
  323. package/skills/xlsx-analysis/scripts/__pycache__/data_profile.cpython-312.pyc +0 -0
  324. package/skills/xlsx-analysis/scripts/__pycache__/xlsx_build.cpython-312.pyc +0 -0
  325. package/skills/xlsx-analysis/scripts/__pycache__/xlsx_check.cpython-312.pyc +0 -0
  326. package/skills/xlsx-analysis/scripts/__pycache__/xlsx_layout.cpython-312.pyc +0 -0
  327. package/skills/xlsx-analysis/scripts/__pycache__/xlsx_toolkit.cpython-312.pyc +0 -0
  328. package/skills/xlsx-analysis/scripts/data_profile.py +391 -0
  329. package/skills/xlsx-analysis/scripts/xlsx_battery.py +389 -0
  330. package/skills/xlsx-analysis/scripts/xlsx_build.py +522 -0
  331. package/skills/xlsx-analysis/scripts/xlsx_check.py +924 -0
  332. package/skills/xlsx-analysis/scripts/xlsx_layout.py +235 -0
  333. package/skills/xlsx-analysis/scripts/xlsx_style.py +28 -66
  334. package/skills/xlsx-analysis/scripts/xlsx_toolkit.py +61 -5
  335. package/skills/xlsx-analysis/trigger-cases.json +59 -0
  336. package/squads/hc-defense.md +47 -0
  337. package/squads/hc-rdarchive.md +110 -0
  338. package/squads/hc-redteam.md +50 -0
  339. package/squads/hc-weekly.md +125 -0
  340. package/src/account.js +1 -1
  341. package/src/acp.js +1 -0
  342. package/src/advisor.js +1 -1
  343. package/src/agent.js +1 -1
  344. package/src/api.js +1 -1
  345. package/src/archaeology.js +1 -0
  346. package/src/ask-ui.js +1 -0
  347. package/src/assets-import.js +1 -1
  348. package/src/autofix.js +1 -1
  349. package/src/automation-tools.js +1 -1
  350. package/src/automation.js +1 -1
  351. package/src/autorun.js +1 -1
  352. package/src/banner.js +1 -1
  353. package/src/capability-probe.js +1 -0
  354. package/src/checkpoints.js +1 -1
  355. package/src/code-tools.js +1 -0
  356. package/src/codeindex.js +1 -1
  357. package/src/codemode.js +1 -0
  358. package/src/command-bridge.js +1 -0
  359. package/src/command-ui.js +1 -0
  360. package/src/commands.js +1 -1
  361. package/src/compaction.js +1 -1
  362. package/src/computer.js +1 -1
  363. package/src/config.js +1 -1
  364. package/src/consult.js +1 -1
  365. package/src/context-report.js +1 -1
  366. package/src/context-window.js +1 -0
  367. package/src/context.js +1 -1
  368. package/src/crew.js +1 -0
  369. package/src/crush.js +1 -0
  370. package/src/daemon.js +1 -1
  371. package/src/decisions.js +1 -1
  372. package/src/depaudit.js +1 -0
  373. package/src/device.js +1 -1
  374. package/src/diagram-draw.js +1 -0
  375. package/src/diagram-layouts.js +1 -0
  376. package/src/diagram-raster.js +1 -0
  377. package/src/diagram.js +1 -0
  378. package/src/dictation.js +1 -0
  379. package/src/diffview.js +1 -1
  380. package/src/doctor.js +1 -1
  381. package/src/docx-tools.js +1 -0
  382. package/src/engineering.js +1 -0
  383. package/src/errkind.js +1 -1
  384. package/src/evidence.js +1 -0
  385. package/src/executors.js +1 -1
  386. package/src/expert-catalog.js +1 -1
  387. package/src/experts-store.js +1 -1
  388. package/src/experts.js +1 -1
  389. package/src/external-agents.js +1 -0
  390. package/src/forks.js +1 -1
  391. package/src/fs-observe.js +1 -0
  392. package/src/gitflow.js +1 -1
  393. package/src/goalround.js +1 -0
  394. package/src/hooks.js +1 -1
  395. package/src/ide.js +1 -1
  396. package/src/input.js +1 -1
  397. package/src/insights.js +1 -1
  398. package/src/jobs.js +1 -0
  399. package/src/kbsync.js +1 -1
  400. package/src/lsp.js +1 -0
  401. package/src/mcp-apps.js +1 -0
  402. package/src/mcp.js +1 -1
  403. package/src/memory.js +1 -1
  404. package/src/notify.js +1 -1
  405. package/src/permissions.js +1 -1
  406. package/src/plan-limits.js +1 -0
  407. package/src/policy.js +1 -0
  408. package/src/pptx-tools.js +1 -0
  409. package/src/presence.js +1 -1
  410. package/src/privatedir.js +1 -0
  411. package/src/pyruntime.js +1 -1
  412. package/src/radar.js +1 -0
  413. package/src/render.js +1 -1
  414. package/src/repl.js +1 -1
  415. package/src/report-tools.js +1 -0
  416. package/src/routing.js +1 -0
  417. package/src/sandbox-probe.js +1 -0
  418. package/src/sandbox-win-launcher.mjs +156 -0
  419. package/src/sandbox.js +1 -0
  420. package/src/scan.js +1 -1
  421. package/src/schedule.js +1 -1
  422. package/src/scopecreep.js +1 -0
  423. package/src/sdk.js +1 -0
  424. package/src/selection.js +1 -0
  425. package/src/session-events.js +1 -0
  426. package/src/session.js +1 -1
  427. package/src/sessionindex.js +1 -0
  428. package/src/sessionlog.js +1 -0
  429. package/src/skill-catalog.js +1 -0
  430. package/src/skill-lint.js +1 -0
  431. package/src/skill-optimize.js +1 -0
  432. package/src/skill-scan.js +1 -0
  433. package/src/skills.js +1 -1
  434. package/src/spill.js +1 -0
  435. package/src/squad.js +1 -1
  436. package/src/subagent.js +1 -1
  437. package/src/surface-state.js +1 -0
  438. package/src/tapd.js +1 -0
  439. package/src/terminal-select.js +1 -0
  440. package/src/terminal.js +1 -0
  441. package/src/test-runner.js +1 -0
  442. package/src/todo.js +1 -1
  443. package/src/toolpipe.js +1 -0
  444. package/src/tools.js +1 -1
  445. package/src/toon.js +1 -0
  446. package/src/transcript.js +1 -1
  447. package/src/tui/app.js +1 -1
  448. package/src/tui/command-menu.js +1 -0
  449. package/src/tui/progress.js +1 -0
  450. package/src/tui/scroll.js +1 -0
  451. package/src/tui/welcome.js +1 -0
  452. package/src/tui/workbench.js +1 -0
  453. package/src/ui-spec.js +1 -0
  454. package/src/uitree.js +1 -0
  455. package/src/uninstall.js +1 -1
  456. package/src/vision.js +1 -1
  457. package/src/visual.js +1 -1
  458. package/src/voice-form.js +1 -0
  459. package/src/voice.js +1 -0
  460. package/src/watch.js +1 -1
  461. package/src/web-audit.js +1 -0
  462. package/src/web-cdp.js +1 -0
  463. package/src/web-inspect.js +1 -0
  464. package/src/websearch.js +1 -0
  465. package/src/weekly.js +1 -0
  466. package/src/workflow.js +1 -0
  467. package/src/worklog.js +1 -0
  468. package/src/xlsx-tools.js +1 -0
  469. package/ui/command-picker.js +79 -0
  470. package/skills/ab-testing/scripts/__pycache__/ab_test.cpython-312.pyc +0 -0
  471. package/skills/accounting-ops/scripts/__pycache__/acct_tools.cpython-312.pyc +0 -0
  472. package/skills/anomaly-detection/scripts/__pycache__/anomaly.cpython-312.pyc +0 -0
  473. package/skills/audit-assist/scripts/__pycache__/audit_sampling.cpython-312.pyc +0 -0
  474. package/skills/banking-credit/scripts/__pycache__/credit_metrics.cpython-312.pyc +0 -0
  475. package/skills/data-report-pro/scripts/__pycache__/bigdata.cpython-312.pyc +0 -0
  476. package/skills/data-wrangling/scripts/__pycache__/join_tools.cpython-312.pyc +0 -0
  477. package/skills/ecommerce-ops/scripts/__pycache__/gmv_decompose.cpython-312.pyc +0 -0
  478. package/skills/funnel-cohort/scripts/__pycache__/funnel.cpython-312.pyc +0 -0
  479. package/skills/management-accounting/scripts/__pycache__/costing.cpython-312.pyc +0 -0
  480. package/skills/manufacturing-quality/scripts/__pycache__/spc.cpython-312.pyc +0 -0
  481. package/skills/marketing-analytics/scripts/__pycache__/rfm.cpython-312.pyc +0 -0
  482. package/skills/optimization-solver/scripts/__pycache__/solver.cpython-312.pyc +0 -0
  483. package/skills/pivot-crosstab/scripts/__pycache__/pivot_tools.cpython-312.pyc +0 -0
  484. package/skills/portfolio-analysis/scripts/__pycache__/portfolio.cpython-312.pyc +0 -0
  485. package/skills/procurement-supply/scripts/__pycache__/supply.cpython-312.pyc +0 -0
  486. package/skills/production-planning/scripts/__pycache__/mrp_capacity.cpython-312.pyc +0 -0
  487. package/skills/project-management/scripts/__pycache__/cpm.cpython-312.pyc +0 -0
  488. package/skills/quant-analysis/scripts/__pycache__/quant.cpython-312.pyc +0 -0
  489. package/skills/real-estate-property/scripts/__pycache__/property_calc.cpython-312.pyc +0 -0
  490. package/skills/regression-forecast/scripts/__pycache__/regress.cpython-312.pyc +0 -0
  491. package/skills/securities-research/scripts/__pycache__/valuation.cpython-312.pyc +0 -0
  492. package/skills/statistical-testing/scripts/__pycache__/stat_tests.cpython-312.pyc +0 -0
  493. package/skills/treasury-mgmt/scripts/__pycache__/cashflow_forecast.cpython-312.pyc +0 -0
@@ -0,0 +1,349 @@
1
+ #!/usr/bin/env python3
2
+ # 报告引擎压测台:图表引擎 / 财务测算 / 项目事实清单。改了这三个脚本中任何一个,必须重跑。
3
+ #
4
+ # [1/3] 图表:每种图型 × 随机数据 N 份,断言出图成功、PNG 是按版心宽 300dpi 出的、
5
+ # 数值标注之间不重叠(逐个量文字框)、同一张图的标注小数位一致;
6
+ # 再加一组「必须拒绝」的输入(双纵轴、系列与类别数对不上、负值饼图、>8 个系列),断言报错而不是硬画。
7
+ # [2/3] 财务:教科书算例对答案;随机假设下的恒等式(IRR 处 NPV≈0、回收期落在累计由负转正的年份里、
8
+ # 节约额永不超过被节约的支出、税后 NPV ≤ 税前 NPV、敏感性临界点处 NPV≈0)。
9
+ # [3/3] 取证:合成代码库里埋一个口令,断言输出里一个字都不出;同步副本只算一次。
10
+ #
11
+ # 用法:python report_battery.py [份数] (出图部分需要 matplotlib:用托管运行时的 python 跑)
12
+
13
+ import json
14
+ import os
15
+ import random
16
+ import shutil
17
+ import sys
18
+ import tempfile
19
+
20
+ HERE = os.path.dirname(os.path.abspath(__file__))
21
+ sys.path.insert(0, HERE)
22
+
23
+ import fin_model as F # noqa: E402
24
+ import project_facts as PF # noqa: E402
25
+
26
+ try:
27
+ import chart_render as CR # noqa: E402
28
+ HAS_MPL = True
29
+ except Exception: # 系统 python 没装 matplotlib:图表段跳过并说明
30
+ HAS_MPL = False
31
+
32
+
33
+ def rnd_series(rng, n_cat, n_s, lo=5, hi=900, neg=False):
34
+ return [{'name': f'系列{i + 1}', 'values': [round(rng.uniform(-hi / 3 if neg else lo, hi), rng.choice([0, 1, 2]))
35
+ for _ in range(n_cat)]} for i in range(n_s)]
36
+
37
+
38
+ def rnd_spec(rng, t):
39
+ n_cat = rng.randint(2, 9)
40
+ cats = [str(2026 + i) if rng.random() < 0.5 else rng.choice(['华东', '华南', '华北', '西南', '研发人员人工',
41
+ '算力与云资源', '测试', '推广', '预备费']) + str(i)
42
+ for i in range(n_cat)]
43
+ if t in ('bar', 'hbar'):
44
+ return {'type': t, 'unit': '万元', 'categories': cats, 'series': rnd_series(rng, n_cat, rng.randint(1, 3), neg=rng.random() < 0.2)}
45
+ if t in ('stacked', 'hstacked'):
46
+ return {'type': t, 'unit': '万元', 'categories': cats, 'series': rnd_series(rng, n_cat, rng.randint(2, 4))}
47
+ if t in ('line', 'area'):
48
+ return {'type': t, 'unit': '%', 'categories': cats, 'series': rnd_series(rng, n_cat, 1 if t == 'area' else rng.randint(1, 4), neg=True)}
49
+ if t == 'pie':
50
+ return {'type': 'pie', 'unit': '万元', 'categories': cats, 'series': rnd_series(rng, n_cat, 1)}
51
+ if t == 'waterfall':
52
+ return {'type': 'waterfall', 'unit': '万元', 'items': [{'name': c, 'value': round(rng.uniform(-80, 300), 1)} for c in cats]}
53
+ if t == 'tornado':
54
+ base = round(rng.uniform(100, 600), 2)
55
+ return {'type': 'tornado', 'unit': '万元', 'metric': 'NPV', 'base': base,
56
+ 'items': [{'name': c, 'low': round(base - rng.uniform(5, 300), 2), 'high': round(base + rng.uniform(5, 300), 2),
57
+ 'low_label': '-20%', 'high_label': '+20%'} for c in cats[:6]]}
58
+ if t == 'gantt':
59
+ tasks, m = [], rng.randint(1, 12)
60
+ for i in range(rng.randint(2, 9)):
61
+ s = m + rng.randint(0, 3)
62
+ e = s + rng.randint(0, 5)
63
+ tasks.append({'name': f'任务{i + 1}', 'start': f'{2026 + (s - 1) // 12}-{(s - 1) % 12 + 1:02d}',
64
+ 'end': f'{2026 + (e - 1) // 12}-{(e - 1) % 12 + 1:02d}', 'group': f'阶段{i // 3 + 1}'})
65
+ m = s + 1
66
+ return {'type': 'gantt', 'tasks': tasks, 'today': '2026-09-23',
67
+ 'milestones': [{'name': '验收', 'date': tasks[-1]['end'] + '-28'}]}
68
+ return {'type': 'matrix', 'items': [{'id': f'R{i + 1}', 'name': f'风险{i + 1}', 'p': rng.randint(1, 5), 'i': rng.randint(1, 5)}
69
+ for i in range(rng.randint(1, 9))]}
70
+
71
+
72
+ def label_boxes(fig):
73
+ """图里所有数值标注(annotate 出的 Text)的像素框。"""
74
+ import matplotlib.text as mtext
75
+ r = fig.canvas.get_renderer()
76
+ boxes = []
77
+ for ax in fig.axes:
78
+ for ch in ax.get_children():
79
+ if isinstance(ch, mtext.Annotation) and ch.get_text().strip():
80
+ bb = ch.get_window_extent(renderer=r)
81
+ boxes.append((bb.x0, bb.y0, bb.x1, bb.y1, ch.get_text()))
82
+ return boxes
83
+
84
+
85
+ def fig_text_boxes(fig):
86
+ """画在 figure 上的文字(单位、图例、图下注)。"""
87
+ r = fig.canvas.get_renderer()
88
+ out = []
89
+ for t in fig.texts:
90
+ if t.get_text().strip():
91
+ bb = t.get_window_extent(renderer=r)
92
+ out.append((bb.x0, bb.y0, bb.x1, bb.y1, t.get_text()[:20]))
93
+ return out
94
+
95
+
96
+ def overlaps(boxes):
97
+ bad = []
98
+ for i in range(len(boxes)):
99
+ for j in range(i + 1, len(boxes)):
100
+ a, b = boxes[i], boxes[j]
101
+ if a[0] < b[2] - 1 and b[0] < a[2] - 1 and a[1] < b[3] - 1 and b[1] < a[3] - 1:
102
+ bad.append((a[4], b[4]))
103
+ return bad
104
+
105
+
106
+ # 真实翻车过的输入固定成回归用例(随机生成器造不出「里程碑扎堆 + 长任务名」这种组合)
107
+ REGRESSION = [
108
+ {'type': 'gantt', 'title': 'A/B 实施进度', 'today': '2026-09-01',
109
+ 'tasks': [{'name': '试用问题修复与跨端一致性收敛', 'start': '2026-10', 'end': '2027-01', 'group': '完善收敛期'},
110
+ {'name': '支付与订阅闭环打通、会员正式收费', 'start': '2026-11', 'end': '2027-02', 'group': '完善收敛期'},
111
+ {'name': '私有化交付标准化与交付手册', 'start': '2026-12', 'end': '2027-03', 'group': '交付突破期'},
112
+ {'name': '规模化运营与产品迭代', 'start': '2027-07', 'end': '2031-12', 'group': '运营增长期'}],
113
+ 'milestones': [{'name': '试用问题修复完成', 'date': '2027-01-31'}, {'name': '会员订阅正式收费', 'date': '2027-02-28'},
114
+ {'name': '私有化交付标准件发布', 'date': '2027-03-31'}, {'name': '首批私有化客户验收', 'date': '2027-06-30'},
115
+ {'name': '累计净现金流转正', 'date': '2030-12-31'}]},
116
+ {'type': 'gantt', 'title': '两个里程碑挨着', 'tasks': [{'name': '开发', 'start': '2026-10', 'end': '2027-03'}],
117
+ 'milestones': [{'name': '方案评审通过', 'date': '2026-10-31'}, {'name': '原型演示', 'date': '2026-11-15'}]},
118
+ {'type': 'gantt', 'title': '五个分组(图例一行放不下)', 'today': '2026-09-23',
119
+ 'tasks': [{'name': f'任务{i}', 'start': f'2026-{10 + i % 3:02d}', 'end': f'2027-{1 + i % 6:02d}',
120
+ 'group': g} for i, g in enumerate(['产品能力', '交付能力', '安全合规', '商业化', '工程基础', '产品能力'])],
121
+ 'milestones': [{'name': '首个私有化项目验收', 'date': '2027-01-31'}, {'name': '付费闭环正式上线', 'date': '2027-02-28'}]},
122
+ {'type': 'bar', 'unit': '万元', 'categories': ['2027', '2028'],
123
+ 'series': [{'name': f'第{i}条业务线(含私有化交付)', 'values': [10 + i, 20 + i]} for i in range(8)], 'labels': 'none'},
124
+ {'type': 'gantt', 'title': '八个里程碑 + 图下注(图注不许被截断)', 'today': '2026-09-24',
125
+ 'tasks': [{'name': '稳定性与性能收口', 'start': '2026-10', 'end': '2026-12'},
126
+ {'name': '商业运营与持续演进', 'start': '2027-10', 'end': '2031-09'}],
127
+ 'milestones': [{'name': n, 'date': d} for n, d in [('压测基线达标', '2027-01-01'), ('交付包发布', '2027-03-01'),
128
+ ('等保测评通过', '2027-05-01'), ('四端正式上架', '2027-08-01'), ('运营期启动', '2027-10-01'),
129
+ ('首批私有化客户验收', '2027-11-15'), ('年度复盘与规划', '2027-12-20'), ('累计净现金流转正', '2030-06-30')]],
130
+ 'note': '数据来源:项目进度计划(2026-09-24 编制),里程碑判定标准见表 6-2;运营期按 5 年计。'},
131
+ {'type': 'tornado', 'unit': '万元', 'metric': 'NPV', 'base': 518.77,
132
+ 'items': [{'name': '经营成本', 'low': 862.78, 'high': 173.67, 'low_label': '-20%', 'high_label': '+20%'},
133
+ {'name': '营业收入', 'low': 274.09, 'high': 763.26, 'low_label': '-20%', 'high_label': '+20%'}]},
134
+ ]
135
+
136
+
137
+ def charts(n, work):
138
+ import matplotlib.pyplot as plt
139
+ rng = random.Random(7)
140
+ types = ['bar', 'hbar', 'stacked', 'hstacked', 'line', 'area', 'pie', 'waterfall', 'tornado', 'gantt', 'matrix']
141
+ fails = []
142
+ orig_close = plt.close
143
+ specs = [(types[k % len(types)], None) for k in range(n)] + [(r['type'], r) for r in REGRESSION]
144
+ for k, (t, fixed) in enumerate(specs):
145
+ spec = fixed or rnd_spec(rng, t)
146
+ out = os.path.join(work, f'c{k}.png')
147
+ captured = {}
148
+ plt.close = lambda fig=None: captured.setdefault('fig', fig) # 拦住关闭,留下 figure 量标注
149
+ try:
150
+ res = CR.render(spec, out)
151
+ except CR.SpecError as e:
152
+ fails.append((t, f'合法随机输入被拒:{e}', spec))
153
+ continue
154
+ except Exception as e:
155
+ fails.append((t, f'引擎异常:{type(e).__name__}: {e}', spec))
156
+ continue
157
+ finally:
158
+ plt.close = orig_close
159
+ fig = captured.get('fig')
160
+ from PIL import Image
161
+ with Image.open(out) as im:
162
+ w_px = im.size[0]
163
+ dpi = (im.info.get('dpi') or (0, 0))[0]
164
+ if abs(w_px - round(res['width_cm'] / 2.54 * 300)) > 2 or round(dpi) != 300:
165
+ fails.append((t, f'出图尺寸不对:{w_px}px @ {dpi}dpi', spec))
166
+ if not os.path.exists(os.path.splitext(out)[0] + '.svg'):
167
+ fails.append((t, '缺同名 SVG', spec))
168
+ if fig is not None and t not in ('pie', 'matrix'):
169
+ bad = overlaps(label_boxes(fig))
170
+ if bad:
171
+ fails.append((t, f'数值标注互相压住:{bad[:3]}', spec))
172
+ if fig is not None and t == 'gantt' and spec.get('milestones'):
173
+ shown = ''.join(b[4] for b in label_boxes(fig)) + ''.join(tx.get_text() for tx in fig.texts)
174
+ shown = shown.replace('\n', '')
175
+ lost = [m['name'] for m in spec['milestones'] if m['name'] not in shown]
176
+ if lost:
177
+ fails.append((t, f'里程碑在图上丢了(标注和图注里都找不到):{lost}', spec))
178
+ if fig is not None:
179
+ W, H = fig.bbox.width, fig.bbox.height
180
+ out_of = [b[4] for b in label_boxes(fig) + fig_text_boxes(fig) if b[0] < -1 or b[2] > W + 1 or b[1] < -1 or b[3] > H + 1]
181
+ if out_of:
182
+ fails.append((t, f'文字出了画布(会被裁掉):{out_of[:3]}', spec))
183
+ if t == 'tornado' and min(min(it['low'], it['high']) for it in spec['items']) >= 0:
184
+ ticks = [tk for tk in fig.axes[0].get_xticks()]
185
+ if any(tk < 0 for tk in ticks):
186
+ fails.append((t, f'数据全为正却标出负刻度:{ticks}', spec))
187
+ nums = [b[4].split('(')[0].replace(',', '').lstrip('+-') for b in label_boxes(fig)]
188
+ decs = {len(x.split('.')[1]) if '.' in x else 0 for x in nums if x.replace('.', '').isdigit()}
189
+ if len(decs) > 1:
190
+ fails.append((t, f'同一张图标注小数位不一致:{sorted(decs)}', spec))
191
+ if fig is not None:
192
+ orig_close(fig)
193
+ must_reject = [
194
+ ({'type': 'line', 'y2': True, 'categories': ['a', 'b'], 'series': [{'name': 'x', 'values': [1, 2]}]}, '双纵轴'),
195
+ ({'type': 'bar', 'categories': ['a', 'b'], 'series': [{'name': 'x', 'values': [1]}]}, '值与类别数不符'),
196
+ ({'type': 'pie', 'categories': ['a', 'b'], 'series': [{'values': [3, -1]}]}, '负值饼图'),
197
+ ({'type': 'bar', 'categories': ['a'], 'series': [{'name': str(i), 'values': [i]} for i in range(9)]}, '9 个系列'),
198
+ ({'type': 'gantt', 'tasks': [{'name': 'x', 'start': '2027-05', 'end': '2027-01'}]}, '结束早于开始'),
199
+ ({'type': 'matrix', 'items': [{'p': 6, 'i': 1}]}, '可能性超出 1~5'),
200
+ ({'type': 'radar'}, '不认识的图型'),
201
+ ]
202
+ rejected = 0
203
+ for spec, why in must_reject:
204
+ try:
205
+ CR.render(spec, os.path.join(work, 'x.png'))
206
+ fails.append(('reject', f'本该拒绝却画了:{why}', spec))
207
+ except CR.SpecError:
208
+ rejected += 1
209
+ return fails, rejected, len(must_reject)
210
+
211
+
212
+ def finance(n):
213
+ fails = []
214
+ # 教科书算例
215
+ r = F.run({'years': 5, 'discount_rate': 0.1, 'investment': [{'name': 'a', 'amount': 100}],
216
+ 'revenue': [{'name': 'r', 'per_year': 30}], 'costs': [{'name': 'c', 'per_year': 0}]})
217
+ i = r['indicators']['pre_tax']
218
+ for k, v, want in (('npv', i['npv'], 12.476), ('irr', i['irr'], 0.152382), ('payback', i['payback'], 4.3333),
219
+ ('payback_dynamic', i['payback_dynamic'], 5.2633)):
220
+ if abs(v - want) > 1e-3:
221
+ fails.append(('教科书', f'{k}={v} 期望 {want}'))
222
+ # 情景方向:实测模型给悲观情景设了「收入×0.6、成本×0.8」——必须预警;方向对的情景不能误报
223
+ base_spec = {'years': 5, 'investment': [{'name': 'a', 'amount': 400}],
224
+ 'revenue': [{'name': 'r', 'values': [200, 300, 400, 500, 600]}],
225
+ 'costs': [{'name': '上游', 'pct_of_revenue': 0.35}, {'name': '人力', 'per_year': 80}]}
226
+ w_bad = F.run({**base_spec, 'scenarios': {'悲观': {'revenue': 0.6, 'costs': 0.8}, '乐观': {'revenue': 1.3, 'costs': 1.1}}})['warnings']
227
+ w_ok = F.run({**base_spec, 'scenarios': {'悲观': {'revenue': 0.7, 'costs': 1.1}, '乐观': {'revenue': 1.2, 'costs': 0.95}}})['warnings']
228
+ if sum('方向不对' in w for w in w_bad) != 2:
229
+ fails.append(('情景方向', f'方向相反的悲观/乐观情景没被点名:{w_bad}'))
230
+ if any('方向不对' in w for w in w_ok):
231
+ fails.append(('情景方向', f'方向正确的情景被误报:{w_ok}'))
232
+ rng = random.Random(11)
233
+ for k in range(n):
234
+ years = rng.randint(3, 10)
235
+ m = rng.randint(1, 3)
236
+ inv = [{'name': f'投{j}', 'amount': rng.uniform(50, 800), 'schedule': None} for j in range(rng.randint(1, 5))]
237
+ for it in inv:
238
+ w = [rng.random() + 0.01 for _ in range(m)]
239
+ it['schedule'] = [x / sum(w) for x in w]
240
+ spec = {'years': years, 'construction_years': m, 'discount_rate': rng.choice([0.06, 0.08, 0.1, 0.12]),
241
+ 'tax_rate': rng.choice([0, 0.15, 0.25]), 'investment': inv,
242
+ 'revenue': [{'name': f'收{j}', 'values': [rng.uniform(0, 600) * (1 + t * 0.3) for t in range(years)]}
243
+ for j in range(rng.randint(1, 3))],
244
+ 'costs': [{'name': '比例成本', 'pct_of_revenue': rng.uniform(0.05, 0.4)},
245
+ {'name': '固定成本', 'per_year': rng.uniform(10, 150), 'growth': rng.uniform(0, 0.1)}],
246
+ 'savings': [{'name': '节约', 'base_values': [rng.uniform(5, 60) for _ in range(years)], 'rate': rng.uniform(0, 1)}],
247
+ 'scenarios': {'悲观': {'revenue': 0.7, 'costs': 1.1}}}
248
+ try:
249
+ res = F.run(spec)
250
+ except F.ModelError as e:
251
+ fails.append((f'随机{k}', f'合法假设被拒:{e}'))
252
+ continue
253
+ M = F.load(spec)
254
+ cf = F.cashflows(M)
255
+ main = F.main_ncf(M, cf)
256
+ ii = F.indicators(main, M['r'])
257
+ if ii['irr'] is not None and abs(F.npv(main, ii['irr'])) > 1e-4 * max(1, sum(abs(x) for x in main)):
258
+ fails.append((f'随机{k}', f'IRR 处 NPV 不为 0:{F.npv(main, ii["irr"])}'))
259
+ for s in M['savings']:
260
+ if any(v > b + 1e-9 for v, b in zip(s['values'], s['base'])):
261
+ fails.append((f'随机{k}', '节约额超过了被节约的支出'))
262
+ if M['tax'] > 0 and F.npv(cf['post'], M['r']) > F.npv(cf['pre'], M['r']) + 1e-9:
263
+ fails.append((f'随机{k}', '税后 NPV 大于税前'))
264
+ pb = ii['payback']
265
+ if pb is not None:
266
+ cum, T = 0.0, None
267
+ for t, v in enumerate(main):
268
+ prev, cum = cum, cum + v
269
+ if t > 0 and prev < 0 <= cum:
270
+ T = t
271
+ break
272
+ # 年序从 1 起:第 T+1 年累计转正 → 回收期 = T + |上年累计| ÷ 当年净流入,落在 [T, T+1]
273
+ if T is None or not (T - 1e-9 <= pb <= T + 1 + 1e-9):
274
+ fails.append((f'随机{k}', f'回收期 {pb} 不在累计由负转正的那一年(T={T})'))
275
+ for srow in res['sensitivity']:
276
+ sw = srow['switch']
277
+ if sw is None or srow['factor'].startswith('其中'):
278
+ continue
279
+ key = {'营业收入': 'k_rev', '经营成本': 'k_cost', '建设投资': 'k_inv', '成本节约': 'k_sav'}[srow['factor']]
280
+ v = F.npv(F.main_ncf(M, F.cashflows(M, **{key: 1 + sw})), M['r'])
281
+ if abs(v) > 0.5: # switch 四舍五入到 4 位小数,留余量
282
+ fails.append((f'随机{k}', f'{srow["factor"]} 临界点处 NPV={v:.3f}'))
283
+ if not res['conclusion'] or '万元' not in res['conclusion']:
284
+ fails.append((f'随机{k}', '结论句缺失'))
285
+ return fails
286
+
287
+
288
+ def facts(work):
289
+ fails = []
290
+ root = os.path.join(work, 'repo')
291
+ def w(p, s):
292
+ os.makedirs(os.path.dirname(os.path.join(root, p)), exist_ok=True)
293
+ open(os.path.join(root, p), 'w', encoding='utf-8').write(s)
294
+ w('svc/src/main/resources/application.yml',
295
+ 'server:\n port: 9090\nspring:\n application:\n name: svc-a\n datasource:\n password: TopSecret#42\n'
296
+ ' url: jdbc:mysql://10.0.0.8:3306/db?user=root&password=TopSecret#42\n')
297
+ w('svc/src/main/resources/application.properties', 'spring.datasource.password=PropSecret99\nserver.port=9091\n')
298
+ w('docker-compose.yml', 'services:\n db:\n image: mysql:8\n environment:\n MYSQL_ROOT_PASSWORD: ComposeSecret7\n ports:\n - "3306:3306"\n')
299
+ w('a/core/x.js', 'export const x = 1;\n' * 20)
300
+ w('b/core/x.js', 'export const x = 1;\n' * 20)
301
+ res = PF.build(root)
302
+ blob = json.dumps(res, ensure_ascii=False)
303
+ for secret in ('TopSecret#42', 'PropSecret99', 'ComposeSecret7', '10.0.0.8'):
304
+ if secret in blob:
305
+ fails.append(('取证', f'输出里出现了配置值:{secret}'))
306
+ if res['code']['duplicates']['files'] != 1:
307
+ fails.append(('取证', f'同步副本应计 1 个,实际 {res["code"]["duplicates"]["files"]}'))
308
+ if not any(s['name'] == 'svc-a' and s['port'] == '9090' for s in res['services']):
309
+ fails.append(('取证', f'没数出服务端口:{res["services"]}'))
310
+ if not any(sv['image'] == 'mysql:8' and sv['ports'] == ['3306:3306'] for c in res['compose'] for sv in c['services']):
311
+ fails.append(('取证', f'compose 服务没取对:{res["compose"]}'))
312
+ return fails
313
+
314
+
315
+ def main(argv):
316
+ n = next((int(a) for a in argv if a.isdigit()), 120)
317
+ work = tempfile.mkdtemp(prefix='reportbat-')
318
+ bad = 0
319
+ try:
320
+ print(f'[1/3] 图表:{n} 份随机数据 × 11 种图型')
321
+ if HAS_MPL:
322
+ f, rej, tot = charts(n, work)
323
+ for t, why, spec in f[:10]:
324
+ print(f' ✗ {t}: {why}\n {json.dumps(spec, ensure_ascii=False)[:240]}')
325
+ print(f' {"✓" if not f else "✗"} {n + len(REGRESSION) - len([x for x in f if x[0] != "reject"])}/{n + len(REGRESSION)} 份出图合规'
326
+ f'(含 {len(REGRESSION)} 个真实翻车回归用例);必须拒绝的输入 {rej}/{tot} 被拒')
327
+ bad += bool(f)
328
+ else:
329
+ print(' - 跳过:当前 python 没有 matplotlib(用托管运行时的 python 跑这一段)')
330
+ print(f'[2/3] 财务:教科书算例 + {n} 组随机假设的恒等式')
331
+ f = finance(n)
332
+ for k, why in f[:10]:
333
+ print(f' ✗ {k}: {why}')
334
+ print(f' {"✓" if not f else "✗"} 全部恒等式成立' if not f else f' ✗ {len(f)} 处不成立')
335
+ bad += bool(f)
336
+ print('[3/3] 取证:埋了口令的合成代码库')
337
+ f = facts(work)
338
+ for k, why in f:
339
+ print(f' ✗ {k}: {why}')
340
+ print(' ✓ 配置值零泄露、同步副本只算一次、服务与编排取对' if not f else '')
341
+ bad += bool(f)
342
+ finally:
343
+ shutil.rmtree(work, ignore_errors=True)
344
+ print('\n全部通过。' if not bad else f'\n有 {bad} 段未通过。')
345
+ return 1 if bad else 0
346
+
347
+
348
+ if __name__ == '__main__':
349
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,15 @@
1
+ {
2
+ "skill": "report-craft",
3
+ "cases": [
4
+ { "id": "pos-finance", "prompt": "可研报告的财务评价怎么做,帮我算 NPV、IRR 和投资回收期", "shouldTrigger": true },
5
+ { "id": "pos-sensitivity", "prompt": "项目报告里要有投资估算表、现金流量表,还要做敏感性分析", "shouldTrigger": true },
6
+ { "id": "pos-charts", "prompt": "给这份报告配上甘特图、投资构成图和敏感性分析的龙卷风图", "shouldTrigger": true },
7
+ { "id": "pos-facts", "prompt": "把代码库的规模、模块和接口数统计出来写进项目报告里", "shouldTrigger": true },
8
+ { "id": "pos-bp", "prompt": "商业计划书的财务测算和数据图表怎么做才专业", "shouldTrigger": true },
9
+ { "id": "pos-feasibility", "prompt": "编写我们项目的可行性研究报告,技术细节、架构图、功能模块图和各类图表都要专业", "shouldTrigger": true, "lexical": false },
10
+ { "id": "neg-format", "prompt": "把这份 Word 的页边距和字体调成公文格式", "shouldTrigger": false },
11
+ { "id": "neg-excel", "prompt": "分析一下这个 Excel 里的销售数据,做个透视表", "shouldTrigger": false },
12
+ { "id": "neg-slides", "prompt": "做一份产品发布会用的 PPT", "shouldTrigger": false },
13
+ { "id": "neg-weekly", "prompt": "帮我写本周的周报", "shouldTrigger": false }
14
+ ]
15
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "skill": "retail-store-ops",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "门店分析,坪效人效怎么算",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "菜单工程和损耗盘点怎么做",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "选址评分和单店模型怎么建",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次电商 GMV 的拆解归因",
22
+ "shouldTrigger": false
23
+ },
24
+ {
25
+ "id": "neg-2",
26
+ "prompt": "写一份仓储 KPI 报表",
27
+ "shouldTrigger": false
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "skill": "risk-compliance",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "做风险评估和风险登记册",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "内控流程矩阵和合规检查怎么做",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "应急预案和数据合规要点",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次内部审计项目立项",
22
+ "shouldTrigger": false,
23
+ "lexical": false
24
+ },
25
+ {
26
+ "id": "neg-2",
27
+ "prompt": "写一份等保测评整改方案",
28
+ "shouldTrigger": false
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: scope-creep
3
+ description: 变更范围蔓延检查——这次改动是不是跑题了:主要改动集中在哪个模块、哪些文件落在别处、是否顺手改了配置/构建文件、是否悄悄加了依赖、有没有巨型改动块或纯格式改动。当用户说"这次改了些什么/是不是改多了/提交前看一眼/帮我拆一下这次改动/范围是不是太大"时使用,长任务跑完后也应主动自查一次。
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # 变更范围蔓延检查
8
+
9
+ 一次改动最常见的失控形态不是「改错了」,而是**改多了**:跑一个长任务,回来发现顺手改了
10
+ 八个无关文件。每一处单看都说得通,合在一起却成了一次没人能安心评审的提交——
11
+ 评审的人只能整体通过或整体打回,而这两个选择都不对。
12
+
13
+ ## 何时使用
14
+
15
+ - **长任务跑完之后主动自查**(这是最该用它的时刻,也是最容易忘的)
16
+ - 提交或开 PR 之前
17
+ - 用户问「这次改了些什么」「是不是改多了」「帮我拆一下」
18
+
19
+ ## 怎么用
20
+
21
+ 1. 调 `scope_check`。不传 intent 时会自动取当前目标(`/goal` 设过的那句话)作为意图。
22
+ 2. 逐条回答它提的问题,然后二选一:
23
+ - **保留**:在提交信息里写清这个文件为什么必须一起改;
24
+ - **拆分**:`git restore --staged <文件>` 把它挪出本次提交,单独提一次。
25
+ 3. 拆分优先。一次提交只做一件事,是让评审能进行下去的前提。
26
+
27
+ ## 五类信号
28
+
29
+ | 信号 | 该问什么 |
30
+ |---|---|
31
+ | 落在主战场之外 | 这个文件是本次要做的事**必须**带上的吗? |
32
+ | 改到配置/构建文件 | 影响面远超它自身,且最容易在一堆功能改动里被漏看——确认必需,并在提交信息里单独点出来 |
33
+ | 依赖清单有新增 | 引入依赖是需要单独说明的决定(体积、许可证、维护状况、供应链风险),不该混在功能提交里 |
34
+ | 巨型改动块 | 这么大的块评审时几乎必然被囫囵放过。能拆就拆,拆不了就写清它做了什么 |
35
+ | 纯格式调整 | 单独提一次。混在功能改动里会让真正的改动淹没在一片重排里 |
36
+
37
+ ## 边界
38
+
39
+ - **它只提问,不下结论。** 输出是「这几个文件看着不在主战场,是有意的吗」,
40
+ 不是「这些文件是多余的」。很多跨模块改动本来就是必要的——一个接口改了,
41
+ 上下游跟着改是应该的。判断该由人做。
42
+ - **不阻断提交。** 提交前只给提示。一个会拦住正当提交的检查器,两天之内就会被忽略。
43
+ - **改动少于四个文件时不查。** 那时谈不上「蔓延」,报告纯属噪声。
44
+ - **不审质量。** 代码写得对不对、有没有边界问题,那是 `code-review` 技能的事。
45
+ 本技能只回答「该不该包含这些文件」。
@@ -0,0 +1,7 @@
1
+ {
2
+ "cases": [
3
+ { "id": "changed-too-much", "prompt": "这次是不是改多了,帮我看看范围", "shouldTrigger": true },
4
+ { "id": "split-change", "prompt": "提交前看一眼,帮我拆一下这次改动", "shouldTrigger": true },
5
+ { "id": "review-quality", "prompt": "帮我审查这段代码的质量和边界情况", "shouldTrigger": false }
6
+ ]
7
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "skill": "sec-auth",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "接 SSO,OIDC 还是 SAML",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "JWT 怎么吊销,会话还是 token",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "权限模型选 RBAC 还是 ABAC,越权怎么整改",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次等保三级的合规整改",
22
+ "shouldTrigger": false,
23
+ "lexical": false
24
+ },
25
+ {
26
+ "id": "neg-2",
27
+ "prompt": "写一段接口签名的实现",
28
+ "shouldTrigger": false
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "skill": "sec-compliance",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "等保测评临近,三级要求怎么落",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "密评国密改造有哪些落点",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "客户问我们过等保没,开源 License 怎么合规",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次 SSO 单点登录接入",
22
+ "shouldTrigger": false,
23
+ "lexical": false
24
+ },
25
+ {
26
+ "id": "neg-2",
27
+ "prompt": "写一份数据分级分类标准",
28
+ "shouldTrigger": false
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "skill": "securities-chain",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "资本市场诉求跨环节,先看用哪个技能",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "从辅导到上市,整条证券链怎么走",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "董秘全年披露怎么管,端到端排一下",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次公司估值的 DCF 测算",
22
+ "shouldTrigger": false,
23
+ "lexical": false
24
+ },
25
+ {
26
+ "id": "neg-2",
27
+ "prompt": "写一份 IPO 申报材料清单",
28
+ "shouldTrigger": false
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "skill": "securities-research",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "写份研报,公司研究框架怎么搭",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "DCF 和可比估值怎么做",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "业绩点评和招股书分析怎么写",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次持仓组合的再平衡",
22
+ "shouldTrigger": false,
23
+ "lexical": false
24
+ },
25
+ {
26
+ "id": "neg-2",
27
+ "prompt": "写一份上市申报的问询回复",
28
+ "shouldTrigger": false
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "skill": "security-audit",
3
+ "cases": [
4
+ {
5
+ "id": "pos-1",
6
+ "prompt": "帮我做代码安全自查",
7
+ "shouldTrigger": true
8
+ },
9
+ {
10
+ "id": "pos-2",
11
+ "prompt": "这段代码安全吗,OWASP 风险有哪些",
12
+ "shouldTrigger": true
13
+ },
14
+ {
15
+ "id": "pos-3",
16
+ "prompt": "上线安全检查,鉴权和密钥怎么看",
17
+ "shouldTrigger": true
18
+ },
19
+ {
20
+ "id": "neg-1",
21
+ "prompt": "做一次安全评审的威胁建模",
22
+ "shouldTrigger": false,
23
+ "lexical": false
24
+ },
25
+ {
26
+ "id": "neg-2",
27
+ "prompt": "写一份等保测评证据清单",
28
+ "shouldTrigger": false
29
+ }
30
+ ]
31
+ }