@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,235 @@
1
+ # Excel 报表呈现度量与规范内核(xlsx_build 建表 / xlsx_check 体检 共用同一套度量)。
2
+ #
3
+ # 为什么必须共用:建表时算「这一列要多宽」和体检时算「这一列会不会显示成 ####」,
4
+ # 只要用两套度量,就一定会出现「生成端说够宽、体检端说被挤掉」的自相矛盾。
5
+ # 一份度量、两个方向用——与 pptx_layout / docx_layout 同一条纪律。
6
+ #
7
+ # 度量口径(Excel 默认字体 Calibri 11 / 中文等线 11):
8
+ # · 列宽单位是「'0' 字符的宽度」,w 列宽 ≈ (w×7+5) 像素(96dpi);
9
+ # · 中日韩字符按 2 个单位算,数字与半角字母按 1 个;
10
+ # · **数字列宽度不够会显示成 ####**(文本只是溢出,还看得见)——所以宽度检查只对数字列是必修。
11
+ # 估算不可能与 Excel 逐像素一致,所以留了 PAD 余量,报告一律带出「需要 vs 实际」的具体数字。
12
+
13
+ import datetime
14
+ import re
15
+
16
+ PX_PER_UNIT = 7.0 # 一个列宽单位 ≈ 7 像素(Calibri 11 的 '0' 宽)
17
+ PX_BASE = 5.0 # 单元格左右内边距合计 ≈ 5 像素
18
+ DPI = 96.0
19
+ CM_PER_IN = 2.54
20
+ PAD = 2.2 # 列宽余量(单位):估窄了就是 ####,估宽一点最多是留白
21
+ MAX_WIDTH = 60.0 # 单列上限:再宽就该换行或拆列,不是加宽
22
+ MIN_WIDTH = 4.0
23
+
24
+ # A4 可用宽度(厘米),扣掉常规页边距 1.8cm×2
25
+ PAGE = {'A4': {'w': 21.0, 'h': 29.7}, 'A3': {'w': 29.7, 'h': 42.0}}
26
+
27
+
28
+ def disp_len(v, number_format=None):
29
+ """一个值在单元格里**显示出来**有多长(列宽单位)。中日韩按 2 算。
30
+
31
+ 关键是按 number_format 算显示形态而不是按原始值:12345.6 在 '#,##0.00' 下显示为
32
+ '12,345.60'(9 位)而不是 '12345.6'(7 位)——差这 2 位就是 #### 与不 #### 的分界。
33
+ """
34
+ if v is None:
35
+ return 0
36
+ if isinstance(v, bool):
37
+ return 5
38
+ if isinstance(v, (datetime.datetime, datetime.date)):
39
+ return 10 if not number_format or 'h' not in str(number_format).lower() else 19
40
+ if isinstance(v, (int, float)):
41
+ return _num_len(v, number_format)
42
+ s = str(v)
43
+ return sum(2 if ord(ch) > 0x2E7F else 1 for ch in s)
44
+
45
+
46
+ def _num_len(v, fmt):
47
+ fmt = str(fmt or 'General')
48
+ if '%' in fmt:
49
+ dec = _decimals(fmt)
50
+ return len(f'{abs(v) * 100:,.{dec}f}') + (1 if v < 0 else 0) + 1
51
+ if fmt in ('General', '@', ''):
52
+ s = repr(float(v)) if isinstance(v, float) else str(v)
53
+ return len(s.rstrip('0').rstrip('.')) if '.' in s else len(s)
54
+ dec = _decimals(fmt)
55
+ body = f'{abs(v):,.{dec}f}' if ',' in fmt else f'{abs(v):.{dec}f}'
56
+ n = len(body)
57
+ if v < 0:
58
+ n += 2 if '(' in fmt or '(' in fmt else 1
59
+ if '¥' in fmt or '¥' in fmt or '$' in fmt:
60
+ n += 1
61
+ return n
62
+
63
+
64
+ def _decimals(fmt):
65
+ m = re.search(r'\.(0+)', str(fmt))
66
+ return len(m.group(1)) if m else 0
67
+
68
+
69
+ def col_width(values, header=None, number_format=None, min_w=MIN_WIDTH, max_w=MAX_WIDTH):
70
+ """按内容算列宽(Excel 列宽单位)。表头也参与——表头被挤掉比数据被挤掉更常见。"""
71
+ n = max([disp_len(header)] + [disp_len(v, number_format) for v in values] or [0])
72
+ return round(max(min_w, min(n + PAD, max_w)), 2)
73
+
74
+
75
+ def width_needed(values, header=None, number_format=None):
76
+ """不加余量的净需求宽度——体检判「够不够」用它,建表用 col_width(带余量)。"""
77
+ return max([disp_len(header)] + [disp_len(v, number_format) for v in values] or [0])
78
+
79
+
80
+ def width_cm(width_units):
81
+ """列宽单位 → 厘米(用于估算打印页宽)。"""
82
+ return (float(width_units) * PX_PER_UNIT + PX_BASE) / DPI * CM_PER_IN
83
+
84
+
85
+ def print_pages_wide(widths, page='A4', landscape=True, margin_cm=1.8, scale=1.0):
86
+ """这张表打印出来会横跨几页。> 1 就该改横向 / 缩放 / 拆表——打印跨页是报表交付件最常见的丢人现场。"""
87
+ p = PAGE.get(str(page).upper(), PAGE['A4'])
88
+ usable = (p['h'] if landscape else p['w']) - margin_cm * 2
89
+ total = sum(width_cm(w) for w in widths) * float(scale or 1.0)
90
+ return max(1, int(total / usable) + (1 if total % usable > 0.01 else 0)), round(total, 2), round(usable, 2)
91
+
92
+
93
+ # ── 数字格式档位 ───────────────────────────────────────────────────────────
94
+ # 一列一个格式,全表统一——「同一列有的两位小数有的整数」是报表最扎眼的不专业。
95
+ FORMATS = {
96
+ 'amount': '#,##0.00', # 金额:千分位两位
97
+ 'amount0': '#,##0', # 金额(整数元)
98
+ 'accounting': '#,##0.00;[红色](#,##0.00)', # 会计:负数红色括号
99
+ 'int': '#,##0',
100
+ 'percent': '0.0%',
101
+ 'percent2': '0.00%',
102
+ 'date': 'yyyy-mm-dd',
103
+ 'datetime': 'yyyy-mm-dd hh:mm',
104
+ 'month': 'yyyy-mm',
105
+ 'text': '@', # 强制文本:身份证/订单号/前导零编码必须用它
106
+ 'general': 'General',
107
+ }
108
+
109
+ AMOUNT_HINTS = ('金额', '贷方', '借方', '余额', '税额', '价税', '收入', '成本', '费用',
110
+ '单价', '工资', '总额', '应收', '应付', '预收', '预付', '销售额', '利润')
111
+ INT_HINTS = ('数量', '件数', '人数', '笔数', '台数', '个数', '订单数', '次数')
112
+ PCT_HINTS = ('占比', '比率', '率', '百分比', '增幅', '同比', '环比', '完成率', '达成率')
113
+ DATE_HINTS = ('日期', '时间', '月份', '期间', '账期', '年月')
114
+ TEXT_HINTS = ('编码', '编号', '代码', '身份证', '手机', '电话', '卡号', '单号', '工号', '邮编')
115
+
116
+
117
+ def guess_format(header, values=()):
118
+ """按列名 + 取样值猜数字格式。猜不准返回 general——**宁可不猜,也不要猜错**:
119
+ 把订单号猜成数字会丢前导零,把金额猜成文本会让 SUM 得 0,两者都比不加格式更糟。"""
120
+ h = str(header or '')
121
+ if any(k in h for k in TEXT_HINTS):
122
+ return FORMATS['text']
123
+ if any(k in h for k in PCT_HINTS):
124
+ return FORMATS['percent']
125
+ if any(k in h for k in DATE_HINTS):
126
+ return FORMATS['date']
127
+ if any(k in h for k in AMOUNT_HINTS):
128
+ return FORMATS['amount']
129
+ if any(k in h for k in INT_HINTS):
130
+ return FORMATS['int']
131
+ nums = [v for v in values if isinstance(v, (int, float)) and not isinstance(v, bool)]
132
+ if nums and len(nums) >= max(1, len(list(values)) * 0.8):
133
+ return FORMATS['amount'] if any(isinstance(v, float) and v != int(v) for v in nums) else FORMATS['int']
134
+ dates = [v for v in values if isinstance(v, (datetime.date, datetime.datetime))]
135
+ if dates and len(dates) >= max(1, len(list(values)) * 0.8):
136
+ return FORMATS['date']
137
+ return FORMATS['general']
138
+
139
+
140
+ # ── 主题(配色 + 行高 + 边框)───────────────────────────────────────────────
141
+ THEMES = {
142
+ 'navy': {'head_bg': '1F4E79', 'head_fg': 'FFFFFF', 'stripe': 'F2F6FA',
143
+ 'border': 'D9D9D9', 'total_bg': 'DCE6F1', 'title_fg': '1F4E79'},
144
+ 'green': {'head_bg': '1E6B52', 'head_fg': 'FFFFFF', 'stripe': 'F1F8F4',
145
+ 'border': 'D9E6DF', 'total_bg': 'D9EDE3', 'title_fg': '1E6B52'},
146
+ 'mono': {'head_bg': '404040', 'head_fg': 'FFFFFF', 'stripe': 'F5F5F5',
147
+ 'border': 'D0D0D0', 'total_bg': 'E8E8E8', 'title_fg': '303030'},
148
+ 'warm': {'head_bg': 'B3541E', 'head_fg': 'FFFFFF', 'stripe': 'FDF4EE',
149
+ 'border': 'EBD9CC', 'total_bg': 'F7E2D3', 'title_fg': 'B3541E'},
150
+ }
151
+
152
+ PROFILES = {
153
+ 'report': {
154
+ 'name': 'report', 'label': '业务报表(表头深色/斑马纹/冻结/筛选/千分位/打印一页宽)',
155
+ 'theme': 'navy', 'font': '等线', 'font_west': 'Calibri', 'size': 11,
156
+ 'head_size': 11, 'head_bold': True, 'title_size': 14,
157
+ 'stripe': True, 'freeze': True, 'autofilter': True, 'borders': True,
158
+ 'row_height': 18, 'head_height': 22,
159
+ 'print': {'page': 'A4', 'landscape': True, 'fit_width': True, 'repeat_head': True,
160
+ 'margin_cm': 1.8, 'footer_page': True},
161
+ },
162
+ 'plain': {
163
+ 'name': 'plain', 'label': '素表(无底纹、便于再加工与二次透视)',
164
+ 'theme': 'mono', 'font': '等线', 'font_west': 'Calibri', 'size': 11,
165
+ 'head_size': 11, 'head_bold': True, 'title_size': 12,
166
+ 'stripe': False, 'freeze': True, 'autofilter': True, 'borders': True,
167
+ 'row_height': 16, 'head_height': 18,
168
+ 'print': {'page': 'A4', 'landscape': False, 'fit_width': True, 'repeat_head': True,
169
+ 'margin_cm': 1.8, 'footer_page': True},
170
+ },
171
+ 'finance': {
172
+ 'name': 'finance', 'label': '财务报表(会计格式/负数红括号/小计加粗上框线)',
173
+ 'theme': 'navy', 'font': '等线', 'font_west': 'Calibri', 'size': 11,
174
+ 'head_size': 11, 'head_bold': True, 'title_size': 14,
175
+ 'stripe': False, 'freeze': True, 'autofilter': False, 'borders': True,
176
+ 'row_height': 18, 'head_height': 22, 'default_amount': 'accounting',
177
+ 'print': {'page': 'A4', 'landscape': False, 'fit_width': True, 'repeat_head': True,
178
+ 'margin_cm': 1.8, 'footer_page': True},
179
+ },
180
+ }
181
+ PROFILE_NAMES = list(PROFILES)
182
+
183
+
184
+ def profile(name='report'):
185
+ p = PROFILES.get(str(name or 'report').strip(), PROFILES['report'])
186
+ out = {k: (dict(v) if isinstance(v, dict) else v) for k, v in p.items()}
187
+ out['colors'] = dict(THEMES.get(out['theme'], THEMES['navy']))
188
+ return out
189
+
190
+
191
+ # ── 单元格坐标 ─────────────────────────────────────────────────────────────
192
+ def col_letter(idx):
193
+ """1 → A,27 → AA。"""
194
+ s = ''
195
+ while idx > 0:
196
+ idx, r = divmod(idx - 1, 26)
197
+ s = chr(65 + r) + s
198
+ return s
199
+
200
+
201
+ def col_index(letter):
202
+ n = 0
203
+ for ch in str(letter).upper():
204
+ if 'A' <= ch <= 'Z':
205
+ n = n * 26 + ord(ch) - 64
206
+ return n
207
+
208
+
209
+ A1_RE = re.compile(r'(?<![A-Z0-9_])(\$?)([A-Z]{1,3})(\$?)(\d{1,7})(?![A-Z0-9_(])')
210
+ RANGE_RE = re.compile(r'(\$?[A-Z]{1,3}\$?\d{1,7})\s*:\s*(\$?[A-Z]{1,3}\$?\d{1,7})')
211
+ ERR_VALUES = ('#REF!', '#DIV/0!', '#N/A', '#VALUE!', '#NAME?', '#NUM!', '#NULL!', '#SPILL!', '#CALC!')
212
+ VOLATILE = ('TODAY(', 'NOW(', 'RAND(', 'RANDBETWEEN(', 'INDIRECT(', 'OFFSET(')
213
+
214
+
215
+ def self_test():
216
+ p = profile('report')
217
+ assert p['colors']['head_bg'] == '1F4E79'
218
+ assert disp_len('销售额') == 6 and disp_len('abc') == 3
219
+ assert disp_len(12345.6, '#,##0.00') == 9, disp_len(12345.6, '#,##0.00')
220
+ assert disp_len(-12345.6, '#,##0.00') == 10
221
+ assert disp_len(0.1234, '0.0%') == 5, disp_len(0.1234, '0.0%') # '12.3%'
222
+ assert col_width(['甲', '乙'], '销售额(万元)') >= 13
223
+ assert col_letter(1) == 'A' and col_letter(27) == 'AA' and col_index('AA') == 27
224
+ assert guess_format('订单编号') == '@' and guess_format('销售额') == '#,##0.00'
225
+ assert guess_format('完成率') == '0.0%' and guess_format('记账日期') == 'yyyy-mm-dd'
226
+ assert guess_format('说明', ['甲', '乙']) == 'General'
227
+ n, total, usable = print_pages_wide([20] * 20)
228
+ assert n >= 2, (n, total, usable)
229
+ assert print_pages_wide([12, 10, 10])[0] == 1
230
+ print(f'[xlsx_layout] self-test OK · {len(PROFILES)} 档规范 / {len(THEMES)} 套主题 / '
231
+ f'A4 横向可用宽 {print_pages_wide([1])[2]}cm')
232
+
233
+
234
+ if __name__ == '__main__':
235
+ self_test()
@@ -1,71 +1,33 @@
1
- # xlsx 格式化回写助手(经 run_python 执行)。核心入口 write_styled():
2
- # 表头加粗白字深蓝底、冻结首行、按内容自动列宽(中文按 2 宽)、数字/金额/日期格式、斑马纹。
3
- # 直接执行本文件 = 自测:产出 xlsx_style_check.xlsx 并重读校验。
4
- import pandas as pd
5
- from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
6
- from openpyxl.utils import get_column_letter
7
-
8
- HEADER_FILL = PatternFill('solid', fgColor='1F4E79') # 深蓝
9
- STRIPE_FILL = PatternFill('solid', fgColor='F2F6FA') # 斑马浅蓝
10
- THIN = Side(style='thin', color='D9D9D9')
11
- BORDER = Border(left=THIN, right=THIN, top=THIN, bottom=THIN)
12
-
13
-
14
- def _width(v):
15
- """按显示宽度估列宽:CJK 记 2,其他记 1。"""
16
- s = '' if v is None else str(v)
17
- return sum(2 if ord(ch) > 0x2E7F else 1 for ch in s)
18
-
19
-
20
- def write_styled(sheets, path, number_formats=None, stripe=True, max_width=60):
21
- """把 {sheet名: DataFrame} 写成带格式的 xlsx。
22
- number_formats: {列名: 格式},如 {'销售额': '#,##0.00', '占比': '0.0%', '日期': 'yyyy-mm-dd'}。
23
- """
24
- if isinstance(sheets, pd.DataFrame):
1
+ # 兼容垫片:老接口 write_styled() 保留,实现已迁到 xlsx_build.py(建表引擎)。
2
+ #
3
+ # 为什么保留而不是直接删:外部脚本与历史会话里可能还 read_skill_file 到这个文件名。
4
+ # 走垫片的好处是老调用**自动获得新引擎的全部改进**——合计写成 SUBTOTAL 公式、
5
+ # 编号列锁文本、打印缩放一页宽、落盘后自动体检。新代码请直接用 create_sheet 工具,
6
+ # 或 from xlsx_build import from_frames。
7
+ import os
8
+ import sys
9
+
10
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
11
+ from xlsx_build import build, from_frames # noqa: F401,E402
12
+
13
+
14
+ def write_styled(sheets, path, number_formats=None, stripe=True, max_width=60, **kw):
15
+ """{sheet名: DataFrame} → 带格式的 xlsx。number_formats={列名: 格式} 仍然生效。"""
16
+ import pandas as pd
17
+ if hasattr(sheets, 'columns'):
25
18
  sheets = {'Sheet1': sheets}
26
- number_formats = number_formats or {}
27
- with pd.ExcelWriter(path, engine='openpyxl') as xw:
28
- for name, df in sheets.items():
29
- df.to_excel(xw, sheet_name=name[:31], index=False)
30
- ws = xw.sheets[name[:31]]
31
- ws.freeze_panes = 'A2'
32
- for j, col in enumerate(df.columns, start=1):
33
- letter = get_column_letter(j)
34
- head = ws.cell(row=1, column=j)
35
- head.font = Font(bold=True, color='FFFFFF')
36
- head.fill = HEADER_FILL
37
- head.alignment = Alignment(horizontal='center', vertical='center')
38
- fmt = number_formats.get(str(col))
39
- w = _width(col) + 2
40
- for i in range(2, len(df) + 2):
41
- cell = ws.cell(row=i, column=j)
42
- cell.border = BORDER
43
- if fmt:
44
- cell.number_format = fmt
45
- if stripe and i % 2 == 0:
46
- cell.fill = STRIPE_FILL
47
- w = max(w, _width(cell.value) + 2)
48
- ws.column_dimensions[letter].width = min(w, max_width)
49
- return path
50
-
51
-
52
- def verify(path):
53
- """重读校验并打印(验收步骤用):每个 sheet 的形状与首末行。"""
54
- chk = pd.read_excel(path, sheet_name=None)
55
- for s, d in chk.items():
56
- head = d.iloc[0].tolist() if len(d) else '空'
57
- tail = d.iloc[-1].tolist() if len(d) else '空'
58
- print(f'[verify] {s} shape={d.shape} 首行={head} 末行={tail}')
59
- return chk
19
+ nf = number_formats or {}
20
+ specs = []
21
+ for name, df in sheets.items():
22
+ cols = [{'key': str(c), 'header': str(c),
23
+ **({'format': nf[c]} if c in nf else {})} for c in df.columns]
24
+ specs.append({'name': str(name), 'columns': cols,
25
+ 'rows': df.where(pd.notna(df), None).values.tolist()})
26
+ return build({'profile': 'report' if stripe else 'plain', 'sheets': specs, **kw}, path)[0]
60
27
 
61
28
 
62
29
  if __name__ == '__main__':
63
- df = pd.DataFrame({
64
- '地区': ['华东', '华南', '华北', '西南'],
65
- '销售额': [1200.5, 950.25, 870.0, 640.75],
66
- '占比': [0.328, 0.26, 0.238, 0.175],
67
- })
68
- p = write_styled({'销售汇总': df}, 'xlsx_style_check.xlsx',
69
- number_formats={'销售额': '#,##0.00', '占比': '0.0%'})
70
- verify(p)
30
+ import pandas as pd
31
+ df = pd.DataFrame({'地区': ['华东', '华南'], '销售额': [12000.5, 9800.0], '占比': [0.55, 0.45]})
32
+ p = write_styled({'自测': df}, 'xlsx_style_check.xlsx')
71
33
  print('OK', p)
@@ -167,16 +167,43 @@ def detect_header(raw: pd.DataFrame, scan: int = 15) -> int:
167
167
  if not nonnull:
168
168
  continue
169
169
  strs = [v for v in nonnull if isinstance(v, str) and v.strip() and not _looks_number(v)]
170
- kw = sum(any(h in str(v) for h in (AMOUNT_HINTS + DATE_HINTS + ('编码', '名称', '组织', '单位', '摘要', '科目')))
171
- for v in nonnull)
170
+ # 关键词按**整行**数,不限于 body_cols。稀疏表里 body_cols 会收缩到只剩几列,
171
+ # 真表头的特征词(「计划金额」「预计付款日」)恰好落在被排除的列里,
172
+ # 而横幅行的「月份:」「单位:」留在里面——同一个工作簿里,
173
+ # 填了数据的月表表头找对,空模板月表就把横幅当成了表头。
174
+ allv = [v for v in row.tolist() if pd.notna(v)]
175
+ kw = sum(any(h in str(v) for h in (AMOUNT_HINTS + DATE_HINTS
176
+ + ('编码', '名称', '组织', '单位', '摘要', '科目')))
177
+ for v in allv)
172
178
  cover = len(nonnull) / max(1, len(body_cols))
173
- # 覆盖度 + 文字占比 + 关键词命中;关键词权重最高(能一击命中真表头)
174
- score = cover * 1.0 + (len(strs) / max(1, len(nonnull))) * 1.0 + kw * 2.0
179
+ # 整行覆盖度另记一份小权重:**表头铺满数据宽度,标题行只占一格**(常是合并单元格)。
180
+ # 「评审结论」那张表的标题行与真表头在 body_cols 上分数完全相同,
181
+ # 平局按行序取第一行就取成了标题;铺满与否才是这两者的真区别。
182
+ wide = len(allv) / max(1, raw.shape[1])
183
+ score = (cover * 1.0 + (len(strs) / max(1, len(nonnull))) * 1.0
184
+ + kw * 2.0 + wide * 0.5)
185
+ score -= _banner_penalty(allv)
175
186
  if score > best_score:
176
187
  best_i, best_score = i, score
177
188
  return best_i
178
189
 
179
190
 
191
+ def _banner_penalty(cells):
192
+ """「这一行不像表头」的减分。表头是一排**短标签**;下面这两种都不是:
193
+
194
+ · 「月份:2019年01月」「单位:元」——标注横幅,冒号后面跟的是值;
195
+ · 「若需要进行重新评审,重新评审时间:不需要」——整句话。
196
+
197
+ 真实语料里 95 张 sheet 有 34 张把这类行当成了表头(36%),
198
+ 而它们恰恰关键词命中多、分数高。不减分就永远压不住。"""
199
+ if not cells:
200
+ return 0.0
201
+ txt = [str(v) for v in cells]
202
+ labeled = sum(1 for t in txt if re.search(r'[::]\s*\S', t))
203
+ longish = sum(1 for t in txt if len(re.sub(r'\s', '', t)) > 15)
204
+ return 2.0 * (labeled / len(txt)) + 2.0 * (longish / len(txt))
205
+
206
+
180
207
  def _looks_number(v) -> bool:
181
208
  try:
182
209
  float(str(v).replace(',', '').replace(',', ''))
@@ -313,7 +340,36 @@ def reconcile(left, right, left_name='左', right_name='右', tol: float = 0.01,
313
340
 
314
341
  # ── 自测(run_python 直接跑本文件即可验证工具箱可用)─────────────────────────
315
342
  if __name__ == '__main__':
316
- print('自测:to_amount / to_period / reconcile\n' + '-' * 50)
343
+ print('自测:detect_header / to_amount / to_period / reconcile\n' + '-' * 50)
344
+
345
+ # ── detect_header:真实办公表的三种形状,全部取自 sample-data 的真语料 ──
346
+ def _hdr(rows):
347
+ return detect_header(pd.DataFrame(rows).dropna(how='all')
348
+ .dropna(how='all', axis=1).reset_index(drop=True))
349
+
350
+ # ① 标题横幅 + 标注行 + 真表头。**空模板与填了数据的表必须判成同一行**——
351
+ # 这正是修掉的那个 bug:稀疏时 body_cols 收缩,真表头的特征词被排除在外。
352
+ banner = ['XX项目12月资金计划', None, None, None, None]
353
+ label = ['月份:XX年XX月', None, None, None, '单位:元']
354
+ head = ['序号', '计划项目概述', '计划金额', '预计付款日', '备注']
355
+ full = [banner, label, head] + [[i, '工资', 189200, '15日', None] for i in range(1, 12)]
356
+ empty = [banner, label, head, [1, '工资', None, None, None]]
357
+ assert _hdr(full) == 2, _hdr(full)
358
+ assert _hdr(empty) == 2, f'空模板取到行 {_hdr(empty)},应与填了数据的表一致'
359
+
360
+ # ② 表名占一格 + 真表头铺满:铺满与否是这两者的唯一区别(平局时按行序会取错)
361
+ two = [['评审结论', None], ['评审内容', '评审结论'],
362
+ ['某某系统的研发', '修改问题后评审通过'],
363
+ ['若需要进行重新评审,重新评审时间:不需要', None],
364
+ ['时间:2025/1/20', None], ['备注:无', None]]
365
+ assert _hdr(two) == 1, f'取到行 {_hdr(two)},应为真表头「评审内容/评审结论」'
366
+
367
+ # ③ 整句话与「标签:值」都不是表头,哪怕关键词命中多
368
+ assert _hdr([['XX项目研发进度计划表', None, None],
369
+ ['序列', '任务名称', '计划开始'],
370
+ [1, '需求调研', '2025-01-06']]) == 1
371
+
372
+ print(' detect_header 三形状全部命中 ✅')
317
373
  amt = to_amount(pd.Series(['1,234.56', '(2,000.00)', '¥3,000元', '-', '', '4000']))
318
374
  assert list(amt.fillna(-999)) == [1234.56, -2000.0, 3000.0, -999, -999, 4000.0], list(amt)
319
375
  assert str(amt.dtype) == 'float64', amt.dtype # 统一 float64(缺失 np.nan,非 pd.NA)
@@ -0,0 +1,59 @@
1
+ {
2
+ "skill": "xlsx-analysis",
3
+ "purpose": "触发行为规格。CI 按词法跑:正样例须在描述词汇上明显压过近似负样例,且路由到自己。改 description 后必须重跑 skill-lint route。",
4
+ "intentionalOverlap": [
5
+ "excel-analysis-chain",
6
+ "pivot-crosstab",
7
+ "data-report-pro",
8
+ "sql-analysis"
9
+ ],
10
+ "cases": [
11
+ {
12
+ "id": "pos-excel",
13
+ "prompt": "帮我分析这个 Excel 表格",
14
+ "shouldTrigger": true,
15
+ "lexical": false,
16
+ "why": "「分析这个 Excel 表格」是通用入口,落到 excel-analysis-chain(总控路由技能)再由它分发到本技能,正是设计的行为,不是路由错误。词法层分不开总控与其成员,按 skill-lint 的规则交行为层,不往描述里塞噪声词去和自己的总控抢分。"
17
+ },
18
+ {
19
+ "id": "pos-numtext",
20
+ "prompt": "xlsx 里金额列存成了文本,求和结果是 0",
21
+ "shouldTrigger": true
22
+ },
23
+ {
24
+ "id": "pos-pivot",
25
+ "prompt": "把这份 xlsx 按地区透视汇总",
26
+ "shouldTrigger": true
27
+ },
28
+ {
29
+ "id": "pos-recon",
30
+ "prompt": "两个 Sheet 的明细和汇总对账核对一下",
31
+ "shouldTrigger": true
32
+ },
33
+ {
34
+ "id": "pos-report",
35
+ "prompt": "做个 Excel 报表,带合计和图表",
36
+ "shouldTrigger": true
37
+ },
38
+ {
39
+ "id": "pos-inspect",
40
+ "prompt": "这份表格合计不对,数字对不上,检查一下",
41
+ "shouldTrigger": true
42
+ },
43
+ {
44
+ "id": "neg-ppt",
45
+ "prompt": "做一份 PPT 汇报材料",
46
+ "shouldTrigger": false
47
+ },
48
+ {
49
+ "id": "neg-word",
50
+ "prompt": "帮我写一份 Word 项目总结报告",
51
+ "shouldTrigger": false
52
+ },
53
+ {
54
+ "id": "neg-code",
55
+ "prompt": "帮我重构这个模块的代码",
56
+ "shouldTrigger": false
57
+ }
58
+ ]
59
+ }
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: hc-defense
3
+ description: 答辩预演——把方案/材料先交给一个专门挑毛病的质询人打一遍,再由独立评委逐条裁定(adversarial 模式)
4
+ leader: 主持
5
+ mode: adversarial
6
+ when: 要去做答辩/评审/汇报/尽调问询,想先被最难的问题问一遍时;已经定稿只想润色文字的不开团
7
+ ---
8
+
9
+ 答辩的失败极少在表达,几乎都在**没被问过**。一份自己看了十遍的方案,作者已经看不见它的洞。
10
+ 本团的价值不是把方案讲得更好听,是**先让对面把最难的问题问出来**,在真正的会场之前。
11
+
12
+ ## 成员
13
+ - defender | 陈述人 | 完整论证方案:目标、依据、数据、风险与应对 | | proponent
14
+ - critic | 质询人 | 逐条找漏洞、风险、反例与逻辑跳跃 | | opponent
15
+ - judge | 评委 | 独立裁定哪些质询成立、方案需要改什么 | | judge
16
+
17
+ ## 成员人设
18
+ ### defender
19
+ 角色:方案陈述人。
20
+ 工作方法:先讲结论再讲依据;每个关键数字标明来源;主动交代边界与不确定性——**主动说出来的风险不算漏洞,被问出来的才算**。
21
+ 交付标准:完整论证 + 一份「我知道的薄弱处」清单(这份清单越诚实,后面越省事)。
22
+
23
+ ### critic
24
+ 角色:质询人。**你的职责是找出这份方案站不住的地方,不是配合它。**
25
+ 工作方法:按「事实→逻辑→可行性→风险」四层查。事实层看数据来源与口径;逻辑层看结论能不能从依据推出来;
26
+ 可行性层看资源、时间、依赖方是否真的具备;风险层看最坏情况有没有兜底。
27
+ 硬约束:**只许基于给到你的材料反驳,不许编造事实、数据或案例**;每条质询必须指明针对原文哪一句;
28
+ 找不到实质问题就说「这一部分没有实质问题」,**不要为了凑数挑措辞**。
29
+ 交付标准:质询清单,每条含【针对原文】【问题】【为什么这是问题】【期望的回答方向】。
30
+
31
+ ### judge
32
+ 角色:独立评委。
33
+ 工作方法:只看本轮三份产出,不引入新信息。逐条裁定质询是否成立,并说明依据。
34
+ 交付标准:裁定表(质询条目 / 成立与否 / 依据 / 方案需要做的改动),外加一句「若我是评委,最可能追问的一个问题」。
35
+
36
+ ## 预检
37
+ - 只想润色文字/改错别字 → 不开团,直接改
38
+ - 方案还没成形(连初稿都没有)→ 先写初稿,对抗需要一个可被攻击的靶子
39
+ - 要的是「支持我说服别人」而不是「帮我找漏洞」→ 明确告知本团是来挑毛病的,问用户要不要继续
40
+
41
+ ## 工作流
42
+ ### 标准答辩预演(触发:要去答辩/评审/汇报,想先被问一遍)
43
+ 1. defender:基于用户材料给出完整论证 + 自认的薄弱处清单
44
+ 2. critic:拿到全文与原始材料,产出质询清单(硬约束逐条写进任务说明)
45
+ 3. defender:逐条回应质询——能修的修,不能修的如实承认
46
+ 4. judge:独立裁定,产出裁定表
47
+ 交付:修正后的方案 + 被有效反驳因而改动的清单 + 仍未解决需用户拍板的分歧
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: hc-rdarchive
3
+ description: 研发档案工场——按模板成套生成项目研发文档(立项/任务书/实施计划/进度表/预算/验收/评审/周期性),生成即体检、必修清零才交付(review 模式)
4
+ leader: 案山
5
+ mode: review
6
+ when: 需要按研发文档模板成套生成一个项目的全部研发文档(约 50 份 docx+xlsx),或对已有归档做档案体检、按体检结论返修时
7
+ ---
8
+
9
+ **这套文档的价值不在份数,在于摆在一起时对不对得上。** 验收与审计正是摆在一起看的:
10
+ 项目名称、编号、负责人、起止时间要在几十份文件里处处相同;立项定的考核指标要在验收里逐条有实测值;
11
+ 12 期进度报告要各写各期的事。所以本团只有一个数据源——**档案卡**,所有封面字段由它派生;
12
+ 所有产出必须过档案体检,**必修清零**才算做完。
13
+
14
+ **工具由你执行,成员只出内容。** 成员在隔离上下文里**只有只读工具**(可 read_file 读产物取证,不能写文件、不能跑 Python)。
15
+ 所以 `create_project_docs` / `create_doc` / `create_sheet` / `docx_inspect` / `xlsx_inspect`
16
+ **一律由你调用**:成员给你档案卡、正文、表格数据、体检结论的分诊与修改建议,你落地并验证。
17
+ 派发「去跑一下体检」这类任务只会撞权限——要派的是「这份体检报告怎么解读、每条谁来改、怎么改」。
18
+
19
+ ## 成员
20
+ - planner | 立案 | 档案卡:把项目信息收敛成一张卡,作为整套文档的唯一数据源 |
21
+ - writer | 撰之 | 正文主笔:按每类文档各自的职责写正文,各写各的 |
22
+ - sheeter | 度衡 | 表格件:进度表、预算表、评审报告的表格内容与勾稽 |
23
+ - inspector | 察微 | 档案体检:目录级 + 单文档体检,逐条给出必修项与定位 |
24
+ - editor | 润言 | 文风审读:去 AI 味、错别字、字数上限、术语与项目名统一 |
25
+
26
+ ## 成员人设
27
+ ### planner
28
+ 角色:档案规划师。
29
+ 工作方法:先把用户给的零散信息收敛成一张**档案卡**——项目名称(全称,后续全档以此为准)、项目编号、
30
+ 建设单位与部门、负责人/联系人/电话、起止时间、年度、预算总额与科目明细、里程碑与交付物、
31
+ 考核指标(带比较词的目标值,如「识别准确率≥92%」)、章节内容要点。
32
+ 信息缺失时**列清单向主理人要**,不替用户编:编出来的编号和电话会一路错到验收。
33
+ **表单字段一律原样填,不做脱敏**——「联系电话」写成「138****0000」会让全档 42 份文件的
34
+ 这一栏同时不合规(体检判「不是电话号码」);档案卡是内部表单不是对外发布物,
35
+ 真要保护就别把号码交给工具,而不是填一个假的。
36
+ **预算科目必须用研发费用归集口径的固定科目名**(其中:人员工资 / 福利费 / 办公及通讯费 /
37
+ 差旅及交通费 / 服务费 / 测试调试费 / 折旧费用与长期费用摊销 / 其它 …),
38
+ 自造「人员费/设备费」对不上,金额会静默变零——生成工具会把正确科目表回报给主理人,以它为准。
39
+ **章节内容的文档类型名与章节名也以工具回报的规范列表为准**:写错不会报错,
40
+ 只会把正文排到文末,看起来一切正常。
41
+ 预算科目之和必须等于总额,不平当场说明;起止时间要与年度、里程碑自洽。
42
+ 交付标准:一份完整档案卡(JSON 结构),并标注哪些字段是用户给的、哪些是按惯例补的。
43
+
44
+ ### writer
45
+ 角色:正文主笔。
46
+ 工作方法:**每类文档只写它职责内的东西**——项目建议书写「为什么要做」,可研写「能不能做成」,
47
+ 任务书写「谁在什么时间交什么」,进度报告写**本期**实际完成与偏差,验收报告写达标情况。
48
+ 背景介绍可以复用,正文主体必须各写各的:同一段话逐字出现在四种以上不同用途的文档里会被体检判为样板段落。
49
+ 模板在节标题后括号里写明的要求就是硬约束(「项目立项背景(500字内)」「包括立项文件号、合同号、研究起止时间」),
50
+ 按它写。给结论要带数字锚点;不写「进行中/预计完成」这类既不达标也不算不达标的措辞。
51
+ 交付标准:按文档分节的正文内容(可直接注入档案卡的「章节内容」),并说明哪些数据是档案卡给的、哪些需要用户确认。
52
+
53
+ ### sheeter
54
+ 角色:表格件工程师。
55
+ 工作方法:**合计一律写 SUBTOTAL 公式,绝不写算好的常量**——常量合计在改明细后不会更新,也不报错。
56
+ 进度表分计划表与实际表:计划表不填进度值,实际表按季度**累计**(上季度已完成的行要保留实际起止与工时);
57
+ 进度是 0~1 的比例,填 2.0 是量纲错。标记完成的行必须有实际起止日期与实际工时——
58
+ 「说完成了却没有任何完成的痕迹」是体检必抓的。预算表科目之和要等于总额,金额不能存成文本。
59
+ 交付标准:各表的行列结构与数据,并自查三件事:合计是公式、季度表累计自洽、计划与实际的任务列表逐条一致。
60
+
61
+ ### inspector
62
+ 角色:档案体检分诊员。
63
+ 工作方法:**体检由主理人跑,你收到的是报告全文**(`docx_inspect(目录)` 的十二类结论:份数齐全性、
64
+ 跨文档字段一致性、模板残留、结构与签批、指标勾稽、周期性文档雷同度、时间线、表格件语义、
65
+ 项目名一致性、模板字数上限、跨文档样板段落、必备要素)。你做三件事:
66
+ ① **分诊**——逐条判定是真缺陷还是正当做法(如立项三件套共享背景是正当的、
67
+ 纸质签到表原件在线下导致电子件留空是可接受的),拿不准就如实写两种可能,不编确定结论;
68
+ ② **定责**——每条标出该由 writer 还是 sheeter 改,以及具体改成什么;
69
+ ③ **取证**——需要看原文时用 read_file 读产物,把关键片段引出来,别凭报告猜。
70
+ 旧格式(.doc/.xls)读不到的层要明说「没查」,不是「没问题」。
71
+ 交付标准:按必修/建议/提示三档重排的整改清单,每条含〔文件定位|是否真缺陷|责任成员|具体改法〕,
72
+ 并明确回答「必修项还剩几条」。
73
+
74
+ ### editor
75
+ 角色:文风审读。
76
+ 工作方法:用 read_file 通读主理人指定的产物,查四件事——① 项目名全档统一(简称正常,**错一个字**和串项目是必改,肉眼审读发现不了);
77
+ ② 错别字与标点(半角逗号冒号、成对符号);③ AI 味(空洞副词「有效/持续/不断/进一步」堆砌、
78
+ 「首先其次再次」骨架、破折号口癖、段首雷同、通篇无数字锚点);④ 模板残留(「提示:」块、
79
+ 「注:由项目单位如实填写…下同」、XX 占位符、未勾选的选择框)。
80
+ 改法是**给出替换建议**,不是笼统说「文风需优化」:「有效提升」→ 提升了多少。
81
+ 交付标准:逐处修改建议(原文/改后/理由),以及一份「本轮共改 N 处、其中必改 M 处」的小结。
82
+
83
+ ## 预检
84
+ - 只要一份文档(如只写个可研)→ 单派 writer + editor,或主理人直接用 `create_doc`,不全团启动
85
+ - 只是给已有归档做体检 → 你自己跑 `docx_inspect(目录)`,再单派 inspector 分诊,不必过 planner/writer
86
+ - 纯数据分析/做报表(不是研发档案)→ 不是本团菜,转 hc-data
87
+ - 用户还没给项目基本信息 → 先让 planner 列缺失清单向用户要,不要凭空生成一套假数据
88
+ - 要改的是排版格式(字体/字号/页边距)→ 你直接跑 `docx_inspect(path, fix=true)`,不必开团
89
+ - 想把「跑体检」派给成员 → 成员没有写/执行权限,必然撞权限;工具你自己调,派给成员的是判断与内容
90
+
91
+ ## 工作流
92
+ ### 成套生成(触发:按模板生成某项目的全部研发文档)
93
+ 1. planner:产出档案卡;缺失字段列清单,由主理人向用户确认后回填
94
+ 2. writer 与 sheeter:同一轮并行派发——writer 出各文档正文要点,sheeter 出进度/预算/评审表内容(两者 context 均带完整档案卡)
95
+ 3. 主理人:把档案卡 + 正文 + 表格合并,用 `create_project_docs` 生成整套骨架并注入内容
96
+ 4. 主理人:跑 `docx_inspect(生成目录)`(必要时对关键单份/单表补跑 `docx_inspect`/`xlsx_inspect`),
97
+ 把**报告全文**派给 inspector 做分诊定责
98
+ 5. writer / sheeter:按 inspector 定责的必修项逐条返修(谁的产出谁改,主理人转达定位与改法),
99
+ 主理人把修订内容写回文档
100
+ 6. 4→5 循环直至**必修为 0**;随后 editor 通读做文风与项目名统一,主理人落地修改
101
+ 7. 主理人:按检查清单交付,并如实说明哪些建议项未处理及原因
102
+ 交付:整套研发文档(docx+xlsx)+ 档案体检报告(必修 0)+ 未处理建议项说明
103
+
104
+ ### 归档体检与返修(触发:已有一套文档,要查问题或按结论整改)
105
+ 1. 主理人:跑 `docx_inspect(目录)` 与关键单份/单表体检,拿到报告全文
106
+ 2. inspector:分诊定责,给出〔文件定位|是否真缺陷|责任成员|具体改法〕清单
107
+ 3. 主理人:与用户确认整改范围(必修必改;建议项由用户决定)
108
+ 4. writer / sheeter:按范围产出修订内容,主理人写回文档
109
+ 5. 主理人:复跑体检确认必修清零;仍有残留则带着新报告回到第 2 步
110
+ 交付:体检报告(整改前/后对照)+ 已修订文档 + 未整改项及原因