@huicai/cli 2026.712.80880 → 2026.721.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.
- package/README.md +2 -1
- package/bin/huicai.js +83 -0
- package/package.json +2 -2
- package/skills/ab-testing/SKILL.md +58 -0
- package/skills/ab-testing/scripts/__pycache__/ab_test.cpython-312.pyc +0 -0
- package/skills/ab-testing/scripts/ab_test.py +71 -0
- package/skills/academic-writing/SKILL.md +54 -0
- package/skills/accounting-ops/SKILL.md +68 -0
- package/skills/accounting-ops/scripts/__pycache__/acct_tools.cpython-312.pyc +0 -0
- package/skills/accounting-ops/scripts/acct_tools.py +89 -0
- package/skills/ai-agent/SKILL.md +85 -0
- package/skills/ai-agent/references/tool-design-checklist.md +51 -0
- package/skills/ai-aiops/SKILL.md +73 -0
- package/skills/ai-aiops/references/aiops-rollout-checklist.md +36 -0
- package/skills/ai-coding/SKILL.md +89 -0
- package/skills/ai-coding/references/task-brief-template.md +48 -0
- package/skills/ai-compliance/SKILL.md +74 -0
- package/skills/ai-compliance/references/genai-compliance-checklist.md +40 -0
- package/skills/ai-eval/SKILL.md +80 -0
- package/skills/ai-eval/scripts/eval-runner.py +150 -0
- package/skills/ai-llm-app/SKILL.md +90 -0
- package/skills/ai-llm-app/references/llm-integration-checklist.md +39 -0
- package/skills/ai-mlops/SKILL.md +72 -0
- package/skills/ai-mlops/scripts/token-cost-calc.py +108 -0
- package/skills/ai-multimodal/SKILL.md +86 -0
- package/skills/ai-multimodal/scripts/field-validate.py +182 -0
- package/skills/ai-prompt/SKILL.md +75 -0
- package/skills/ai-prompt/references/prompt-template.md +46 -0
- package/skills/ai-rag/SKILL.md +76 -0
- package/skills/ai-rag/scripts/chunk-inspect.py +129 -0
- package/skills/anomaly-detection/SKILL.md +54 -0
- package/skills/anomaly-detection/scripts/__pycache__/anomaly.cpython-312.pyc +0 -0
- package/skills/anomaly-detection/scripts/anomaly.py +99 -0
- package/skills/api-integration/SKILL.md +74 -0
- package/skills/api-integration/references/signing-recipes.md +141 -0
- package/skills/arch-design/SKILL.md +57 -0
- package/skills/arch-distributed/SKILL.md +81 -0
- package/skills/arch-distributed/references/idempotency-review.md +43 -0
- package/skills/arch-multitenant/SKILL.md +73 -0
- package/skills/arch-multitenant/references/tenant-isolation-checklist.md +34 -0
- package/skills/audit-assist/SKILL.md +63 -0
- package/skills/audit-assist/scripts/__pycache__/audit_sampling.cpython-312.pyc +0 -0
- package/skills/audit-assist/scripts/audit_sampling.py +93 -0
- package/skills/audit-chain/SKILL.md +60 -0
- package/skills/banking-credit/SKILL.md +59 -0
- package/skills/banking-credit/scripts/__pycache__/credit_metrics.cpython-312.pyc +0 -0
- package/skills/banking-credit/scripts/credit_metrics.py +53 -0
- package/skills/brand-design/SKILL.md +56 -0
- package/skills/business-plan/SKILL.md +56 -0
- package/skills/capital-ops/SKILL.md +52 -0
- package/skills/cicd-pipeline/SKILL.md +85 -0
- package/skills/cicd-pipeline/references/pipeline-review-checklist.md +39 -0
- package/skills/content-creation/SKILL.md +56 -0
- package/skills/corporate-governance/SKILL.md +56 -0
- package/skills/crawl-chain/SKILL.md +61 -0
- package/skills/customer-service/SKILL.md +51 -0
- package/skills/data-analysis/SKILL.md +46 -0
- package/skills/data-analysis/scripts/cjk_font.py +56 -0
- package/skills/data-chain/SKILL.md +54 -0
- package/skills/data-governance/SKILL.md +54 -0
- package/skills/data-report-pro/SKILL.md +65 -0
- package/skills/data-report-pro/scripts/__pycache__/bigdata.cpython-312.pyc +0 -0
- package/skills/data-report-pro/scripts/bigdata.py +79 -0
- package/skills/data-streaming/SKILL.md +87 -0
- package/skills/data-streaming/references/job-checklist.md +36 -0
- package/skills/data-wrangling/SKILL.md +52 -0
- package/skills/data-wrangling/scripts/__pycache__/join_tools.cpython-312.pyc +0 -0
- package/skills/data-wrangling/scripts/join_tools.py +99 -0
- package/skills/db-es/SKILL.md +68 -0
- package/skills/db-es/scripts/es-health.sh +72 -0
- package/skills/db-migration/SKILL.md +72 -0
- package/skills/db-migration/scripts/checksum-mysql.sql +46 -0
- package/skills/db-migration/scripts/checksum-postgres.sql +39 -0
- package/skills/db-migration/scripts/compare-reports.py +98 -0
- package/skills/db-mysql/SKILL.md +78 -0
- package/skills/db-mysql/scripts/mysql-health.sql +80 -0
- package/skills/db-postgres/SKILL.md +86 -0
- package/skills/db-postgres/scripts/pg-health.sql +67 -0
- package/skills/db-redis/SKILL.md +83 -0
- package/skills/db-redis/scripts/redis-health.sh +92 -0
- package/skills/dev-cpp/SKILL.md +94 -0
- package/skills/dev-cpp/references/cmake-sanitizer-snippets.md +56 -0
- package/skills/dev-cross-platform/SKILL.md +73 -0
- package/skills/dev-cross-platform/references/capability-matrix-template.md +39 -0
- package/skills/dev-csharp/SKILL.md +96 -0
- package/skills/dev-csharp/references/review-checklist.md +37 -0
- package/skills/dev-frontend/SKILL.md +91 -0
- package/skills/dev-frontend/scripts/bundle-budget.py +106 -0
- package/skills/dev-go/SKILL.md +88 -0
- package/skills/dev-go/scripts/go-triage.sh +54 -0
- package/skills/dev-harmony/SKILL.md +64 -0
- package/skills/dev-harmony/references/harmony-checklist.md +40 -0
- package/skills/dev-java/SKILL.md +77 -0
- package/skills/dev-java/scripts/jvm-triage.sh +84 -0
- package/skills/dev-mobile/SKILL.md +82 -0
- package/skills/dev-mobile/references/store-compliance-checklist.md +33 -0
- package/skills/dev-node/SKILL.md +82 -0
- package/skills/dev-node/scripts/node-triage.sh +78 -0
- package/skills/dev-php/SKILL.md +86 -0
- package/skills/dev-php/scripts/fpm-calc.py +48 -0
- package/skills/dev-python/SKILL.md +81 -0
- package/skills/dev-python/scripts/venv-doctor.sh +75 -0
- package/skills/dev-rust/SKILL.md +84 -0
- package/skills/dev-rust/references/cargo-ci-snippets.md +50 -0
- package/skills/dev-toolchain/SKILL.md +78 -0
- package/skills/dev-toolchain/scripts/secret-scan.sh +83 -0
- package/skills/doc-chain/SKILL.md +58 -0
- package/skills/doc-compare/SKILL.md +44 -0
- package/skills/doc-compare/scripts/compare.py +93 -0
- package/skills/docx-author/SKILL.md +39 -0
- package/skills/docx-author/scripts/docx_doc.py +161 -0
- package/skills/ecommerce-ops/SKILL.md +54 -0
- package/skills/ecommerce-ops/scripts/__pycache__/gmv_decompose.cpython-312.pyc +0 -0
- package/skills/ecommerce-ops/scripts/gmv_decompose.py +61 -0
- package/skills/education-training/SKILL.md +53 -0
- package/skills/ehs-safety/SKILL.md +63 -0
- package/skills/email-writing/SKILL.md +52 -0
- package/skills/eng-ai/SKILL.md +74 -0
- package/skills/eng-ai/references/ai-feature-checklist.md +36 -0
- package/skills/eng-architecture/SKILL.md +85 -0
- package/skills/eng-architecture/scripts/capacity-calc.py +100 -0
- package/skills/eng-automation/SKILL.md +84 -0
- package/skills/eng-automation/references/automation-inventory.md +38 -0
- package/skills/eng-automation/references/routine-presets.md +73 -0
- package/skills/eng-collaboration/SKILL.md +76 -0
- package/skills/eng-collaboration/references/collab-templates.md +43 -0
- package/skills/eng-complex-env/SKILL.md +84 -0
- package/skills/eng-complex-env/references/env-dossier-template.md +52 -0
- package/skills/eng-complex-env/scripts/env-recon.sh +152 -0
- package/skills/eng-data-platform/SKILL.md +81 -0
- package/skills/eng-data-platform/references/table-spec-template.md +39 -0
- package/skills/eng-database/SKILL.md +79 -0
- package/skills/eng-database/references/schema-review-checklist.md +37 -0
- package/skills/eng-develop/SKILL.md +76 -0
- package/skills/eng-develop/references/dod-checklist.md +43 -0
- package/skills/eng-docs/SKILL.md +71 -0
- package/skills/eng-docs/references/runbook-template.md +57 -0
- package/skills/eng-efficiency/SKILL.md +75 -0
- package/skills/eng-efficiency/scripts/dora-calc.py +104 -0
- package/skills/eng-infra/SKILL.md +81 -0
- package/skills/eng-infra/references/production-readiness.md +46 -0
- package/skills/eng-integration/SKILL.md +82 -0
- package/skills/eng-integration/references/integration-dossier-template.md +38 -0
- package/skills/eng-legacy/SKILL.md +81 -0
- package/skills/eng-legacy/references/modernization-workbook.md +46 -0
- package/skills/eng-observability/SKILL.md +78 -0
- package/skills/eng-observability/scripts/slo-calc.py +82 -0
- package/skills/eng-ops/SKILL.md +74 -0
- package/skills/eng-ops/references/postmortem-template.md +67 -0
- package/skills/eng-performance/SKILL.md +73 -0
- package/skills/eng-performance/scripts/perf-baseline.py +110 -0
- package/skills/eng-planning/SKILL.md +79 -0
- package/skills/eng-planning/scripts/schedule-calc.py +101 -0
- package/skills/eng-quality/SKILL.md +74 -0
- package/skills/eng-quality/references/test-plan-templates.md +46 -0
- package/skills/eng-release/SKILL.md +78 -0
- package/skills/eng-release/references/release-plan-template.md +36 -0
- package/skills/eng-reliability/SKILL.md +72 -0
- package/skills/eng-reliability/references/resilience-review.md +43 -0
- package/skills/eng-requirements/SKILL.md +86 -0
- package/skills/eng-requirements/references/story-templates.md +47 -0
- package/skills/eng-research/SKILL.md +73 -0
- package/skills/eng-research/references/research-templates.md +42 -0
- package/skills/eng-security/SKILL.md +73 -0
- package/skills/eng-security/references/security-review-checklist.md +33 -0
- package/skills/eng-ux/SKILL.md +85 -0
- package/skills/eng-ux/references/ux-review-checklist.md +36 -0
- package/skills/engineering-chain/SKILL.md +101 -0
- package/skills/engineering-chain/references/eng-health-review.md +37 -0
- package/skills/env-offline/SKILL.md +81 -0
- package/skills/env-offline/scripts/bundle-manifest.sh +94 -0
- package/skills/env-private-deploy/SKILL.md +72 -0
- package/skills/env-private-deploy/references/delivery-templates.md +35 -0
- package/skills/env-xinchuang/SKILL.md +73 -0
- package/skills/env-xinchuang/references/adaptation-matrix-template.md +41 -0
- package/skills/equipment-tpm/SKILL.md +56 -0
- package/skills/equipment-tpm/scripts/oee.py +58 -0
- package/skills/esg-report/SKILL.md +58 -0
- package/skills/esg-report/scripts/carbon_calc.py +61 -0
- package/skills/event-management/SKILL.md +51 -0
- package/skills/excel-analysis-chain/SKILL.md +73 -0
- package/skills/file-ingest/SKILL.md +51 -0
- package/skills/file-ingest/scripts/__pycache__/file_toolkit.cpython-312.pyc +0 -0
- package/skills/file-ingest/scripts/file_toolkit.py +404 -0
- package/skills/finance-analysis/SKILL.md +60 -0
- package/skills/finance-analysis/references/ratios.md +54 -0
- package/skills/finance-analysis/scripts/fin_ratios.py +132 -0
- package/skills/finance-chain/SKILL.md +59 -0
- package/skills/financial-modeling/SKILL.md +58 -0
- package/skills/financial-modeling/scripts/fin_model.py +123 -0
- package/skills/foreign-trade/SKILL.md +54 -0
- package/skills/funnel-cohort/SKILL.md +53 -0
- package/skills/funnel-cohort/scripts/__pycache__/funnel.cpython-312.pyc +0 -0
- package/skills/funnel-cohort/scripts/funnel.py +105 -0
- package/skills/gov-document/SKILL.md +57 -0
- package/skills/hr-chain/SKILL.md +51 -0
- package/skills/hr-operations/SKILL.md +53 -0
- package/skills/info-disclosure/SKILL.md +56 -0
- package/skills/infra-gateway/SKILL.md +85 -0
- package/skills/infra-gateway/references/golive-checklist.md +36 -0
- package/skills/infra-k8s/SKILL.md +78 -0
- package/skills/infra-k8s/scripts/k8s-triage.sh +84 -0
- package/skills/infra-mq/SKILL.md +87 -0
- package/skills/infra-mq/references/mq-review-checklist.md +36 -0
- package/skills/insurance-advisory/SKILL.md +57 -0
- package/skills/internal-audit/SKILL.md +66 -0
- package/skills/ip-management/SKILL.md +54 -0
- package/skills/ipo-listing/SKILL.md +60 -0
- package/skills/it-audit/SKILL.md +56 -0
- package/skills/itsm-ops/SKILL.md +55 -0
- package/skills/knowledge-sop/SKILL.md +51 -0
- package/skills/legal-chain/SKILL.md +55 -0
- package/skills/legal-contract/SKILL.md +58 -0
- package/skills/legal-contract/references/contract-checklists.md +59 -0
- package/skills/litigation-support/SKILL.md +53 -0
- package/skills/logistics-warehouse/SKILL.md +53 -0
- package/skills/logistics-warehouse/scripts/freight_check.py +71 -0
- package/skills/long-doc-analysis/SKILL.md +52 -0
- package/skills/management-accounting/SKILL.md +57 -0
- package/skills/management-accounting/scripts/__pycache__/costing.cpython-312.pyc +0 -0
- package/skills/management-accounting/scripts/costing.py +90 -0
- package/skills/manufacturing-chain/SKILL.md +57 -0
- package/skills/manufacturing-quality/SKILL.md +57 -0
- package/skills/manufacturing-quality/scripts/__pycache__/spc.cpython-312.pyc +0 -0
- package/skills/manufacturing-quality/scripts/spc.py +86 -0
- package/skills/marketing-analytics/SKILL.md +59 -0
- package/skills/marketing-analytics/scripts/__pycache__/rfm.cpython-312.pyc +0 -0
- package/skills/marketing-analytics/scripts/rfm.py +60 -0
- package/skills/marketing-chain/SKILL.md +57 -0
- package/skills/meeting-minutes/SKILL.md +55 -0
- package/skills/metrics-system/SKILL.md +55 -0
- package/skills/negotiation-prep/SKILL.md +56 -0
- package/skills/obs-prometheus/SKILL.md +74 -0
- package/skills/obs-prometheus/references/promql-cheatsheet.md +78 -0
- package/skills/office-automation/SKILL.md +54 -0
- package/skills/okr-review/SKILL.md +44 -0
- package/skills/ops-fleet/SKILL.md +69 -0
- package/skills/ops-fleet/scripts/batch-exec-guard.sh +119 -0
- package/skills/ops-linux/SKILL.md +69 -0
- package/skills/ops-linux/scripts/quick-triage.sh +138 -0
- package/skills/optimization-solver/SKILL.md +53 -0
- package/skills/optimization-solver/scripts/__pycache__/solver.cpython-312.pyc +0 -0
- package/skills/optimization-solver/scripts/solver.py +107 -0
- package/skills/pdf-toolkit/SKILL.md +43 -0
- package/skills/pdf-toolkit/scripts/pdf_ops.py +137 -0
- package/skills/pivot-crosstab/SKILL.md +44 -0
- package/skills/pivot-crosstab/scripts/__pycache__/pivot_tools.cpython-312.pyc +0 -0
- package/skills/pivot-crosstab/scripts/pivot_tools.py +90 -0
- package/skills/policy-analysis/SKILL.md +47 -0
- package/skills/portfolio-analysis/SKILL.md +56 -0
- package/skills/portfolio-analysis/scripts/__pycache__/portfolio.cpython-312.pyc +0 -0
- package/skills/portfolio-analysis/scripts/portfolio.py +78 -0
- package/skills/ppt-chain/SKILL.md +61 -0
- package/skills/pptx-author/SKILL.md +48 -0
- package/skills/pptx-author/scripts/pptx_deck.py +193 -0
- package/skills/pr-comms/SKILL.md +58 -0
- package/skills/pr-comms/references/pr-templates.md +54 -0
- package/skills/procurement-supply/SKILL.md +47 -0
- package/skills/procurement-supply/scripts/__pycache__/supply.cpython-312.pyc +0 -0
- package/skills/procurement-supply/scripts/supply.py +71 -0
- package/skills/product-design/SKILL.md +66 -0
- package/skills/product-design/references/prd-framework.md +60 -0
- package/skills/production-planning/SKILL.md +56 -0
- package/skills/production-planning/scripts/__pycache__/mrp_capacity.cpython-312.pyc +0 -0
- package/skills/production-planning/scripts/mrp_capacity.py +70 -0
- package/skills/project-management/SKILL.md +53 -0
- package/skills/project-management/scripts/__pycache__/cpm.cpython-312.pyc +0 -0
- package/skills/project-management/scripts/cpm.py +84 -0
- package/skills/project-proposal/SKILL.md +54 -0
- package/skills/project-proposal/scripts/budget_sheet.py +90 -0
- package/skills/qa-api-automation/SKILL.md +67 -0
- package/skills/qa-api-automation/references/three-layer-skeleton.md +61 -0
- package/skills/qa-mobile-automation/SKILL.md +70 -0
- package/skills/qa-mobile-automation/references/device-matrix-template.md +34 -0
- package/skills/qa-ui-automation/SKILL.md +80 -0
- package/skills/qa-ui-automation/references/stability-conventions.md +41 -0
- package/skills/quant-analysis/SKILL.md +60 -0
- package/skills/quant-analysis/scripts/__pycache__/quant.cpython-312.pyc +0 -0
- package/skills/quant-analysis/scripts/quant.py +102 -0
- package/skills/real-estate-property/SKILL.md +51 -0
- package/skills/real-estate-property/scripts/__pycache__/property_calc.cpython-312.pyc +0 -0
- package/skills/real-estate-property/scripts/property_calc.py +106 -0
- package/skills/regression-forecast/SKILL.md +52 -0
- package/skills/regression-forecast/scripts/__pycache__/regress.cpython-312.pyc +0 -0
- package/skills/regression-forecast/scripts/regress.py +106 -0
- package/skills/retail-store-ops/SKILL.md +57 -0
- package/skills/retail-store-ops/scripts/store_ops.py +57 -0
- package/skills/risk-compliance/SKILL.md +51 -0
- package/skills/sec-auth/SKILL.md +89 -0
- package/skills/sec-auth/references/auth-review-checklist.md +38 -0
- package/skills/sec-compliance/SKILL.md +74 -0
- package/skills/sec-compliance/references/dengbao-checklist.md +43 -0
- package/skills/securities-chain/SKILL.md +69 -0
- package/skills/securities-research/SKILL.md +58 -0
- package/skills/securities-research/scripts/__pycache__/valuation.cpython-312.pyc +0 -0
- package/skills/securities-research/scripts/valuation.py +93 -0
- package/skills/slides-html/SKILL.md +50 -0
- package/skills/slides-html/scripts/template.html +117 -0
- package/skills/statistical-testing/SKILL.md +51 -0
- package/skills/statistical-testing/scripts/__pycache__/stat_tests.cpython-312.pyc +0 -0
- package/skills/statistical-testing/scripts/stat_tests.py +131 -0
- package/skills/strategy-planning/SKILL.md +53 -0
- package/skills/supply-chain/SKILL.md +53 -0
- package/skills/tax-compliance/SKILL.md +57 -0
- package/skills/tax-compliance/scripts/tax_calc.py +90 -0
- package/skills/tech-research/SKILL.md +55 -0
- package/skills/tech-research/references/research-framework.md +50 -0
- package/skills/tender-bidding/SKILL.md +65 -0
- package/skills/tender-bidding/references/bid-checklist.md +44 -0
- package/skills/translation-pro/SKILL.md +44 -0
- package/skills/treasury-mgmt/SKILL.md +56 -0
- package/skills/treasury-mgmt/scripts/__pycache__/cashflow_forecast.cpython-312.pyc +0 -0
- package/skills/treasury-mgmt/scripts/cashflow_forecast.py +51 -0
- package/skills/web-scraping/SKILL.md +81 -0
- package/skills/web-search/SKILL.md +67 -0
- package/skills/xlsx-analysis/SKILL.md +96 -0
- package/skills/xlsx-analysis/scripts/__pycache__/xlsx_toolkit.cpython-312.pyc +0 -0
- package/skills/xlsx-analysis/scripts/xlsx_style.py +71 -0
- package/skills/xlsx-analysis/scripts/xlsx_toolkit.py +335 -0
- package/src/agent.js +1 -1
- package/src/api.js +1 -1
- package/src/codeindex.js +1 -1
- package/src/commands.js +1 -1
- package/src/config.js +1 -1
- package/src/context.js +1 -1
- package/src/device.js +1 -1
- package/src/doccache.js +1 -0
- package/src/doctor.js +1 -1
- package/src/executors.js +1 -1
- package/src/input.js +1 -1
- package/src/permissions.js +1 -1
- package/src/pyruntime.js +1 -0
- package/src/repl.js +1 -1
- package/src/scan.js +1 -1
- package/src/session.js +1 -1
- package/src/tools.js +1 -1
- package/src/tui/app.js +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-mobile
|
|
3
|
+
description: 移动端开发链(双端 MVVM 单向数据流→Kotlin 协程/Swift 并发要点→生命周期与进程被杀恢复→单一数据源离线架构→启动/卡顿/内存性能预算→包体积审计→权限与隐私合规(个保法/工信部)→双端灰度发布与热修判据→崩溃率红线与符号表管理)。Android/iOS 开发、上架合规整改、崩溃治理、启动优化时载入。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 移动端开发链
|
|
8
|
+
|
|
9
|
+
eng-develop 的移动端原生孙链(Android/Kotlin+iOS/Swift);跨端框架与小程序见 dev-cross-platform;鸿蒙端(ArkTS/三端并存策略)载 **dev-harmony**。
|
|
10
|
+
|
|
11
|
+
## 架构基线
|
|
12
|
+
|
|
13
|
+
MVVM+单向数据流:Android(ViewModel+StateFlow/Compose)/iOS(SwiftUI+Observable 或 UIKit+MVVM);
|
|
14
|
+
状态=不可变数据类,事件上行、状态下行(双向绑定的隐式修改=状态失控之源);
|
|
15
|
+
模块化判据:按特性分模块(编译提速+权责边界),公共层(网络/存储/设计组件)下沉;
|
|
16
|
+
**业务逻辑下沉到与 UI 框架无关的层**(UseCase/Repository)——可单测、可跨端迁移。
|
|
17
|
+
|
|
18
|
+
## 语言要点
|
|
19
|
+
|
|
20
|
+
- Kotlin:协程结构化并发(作用域跟生命周期:viewModelScope/lifecycleScope,**裸 GlobalScope 评审拦**);空安全禁 `!!`(用 ?.、requireNotNull 带消息);data class+copy 做不可变状态;Flow 冷流与 StateFlow 热流分清;
|
|
21
|
+
- Swift:值类型优先(struct 默认,引用语义才 class);**闭包捕获 `[weak self]` 纪律**(逃逸闭包+长生命周期持有=环引用);async/await 迁移(回调金字塔逐层改);Sendable/actor 并发检查渐进开;
|
|
22
|
+
- 双端共同:主线程红线——IO/网络/大 JSON 解析一律下线程(ANR 与卡顿第一来源)。
|
|
23
|
+
|
|
24
|
+
## 生命周期与状态保存
|
|
25
|
+
|
|
26
|
+
**进程随时被杀心智**:后台返回=可能全新进程,关键状态可恢复(SavedStateHandle/StateRestoration),恢复路径要真测(开发者选项"不保留活动"/模拟内存终止);
|
|
27
|
+
配置变更(旋转/分屏/深色)与 ViewModel 边界;
|
|
28
|
+
后台任务双端差异表:Android WorkManager(约束调度)/iOS BGTaskScheduler(机会性,**别承诺后台准点执行**——产品设计要按"尽力而为"来)。
|
|
29
|
+
|
|
30
|
+
## 网络与离线(单一数据源)
|
|
31
|
+
|
|
32
|
+
本地库(Room/CoreData/SQLDelight)=事实源,网络层是同步器——UI 只订阅本地,弱网天然可用;
|
|
33
|
+
弱网设计:超时重试指数退避+抖动;请求合并与增量同步(全量拉取=流量与电量刺客);
|
|
34
|
+
**序列化兼容**:字段增删容错(未知字段忽略/缺字段默认值),服务端灰度期新旧版本并存(api-design 只加不改不删同拍);
|
|
35
|
+
错误分层提示:网络断(可重试)/服务端错(联系客服+traceId)/业务拒绝(按文案)。
|
|
36
|
+
|
|
37
|
+
## 性能预算(每版本对照基线)
|
|
38
|
+
|
|
39
|
+
- **启动**:冷启动预算定数字(如 2s);主线程初始化清单化管理,三方 SDK 懒加载/延迟到首帧后——**SDK 串行初始化是冷启动最大杀手**;启动阶段埋点分段计时(哪段涨了立刻可见);
|
|
40
|
+
- **卡顿**:帧监控常驻;列表:复用+图片按控件尺寸解码(原图直塞=内存与滚动双杀)+分页;主线程 IO 检测(StrictMode/主线程 checker);
|
|
41
|
+
- **内存**:图片缓存设上限;泄漏常客(Android:静态持 Context/Handler 延迟消息;iOS:闭包环引用/NotificationCenter 未移除)用 LeakCanary/Instruments 每版本扫;低内存回调要响应(清缓存)。
|
|
42
|
+
|
|
43
|
+
## 包体积
|
|
44
|
+
|
|
45
|
+
审计常态化:每版本体积 diff 入发布报告(eng-release);
|
|
46
|
+
手段:资源(webp/矢量/按密度分发 App Bundle)/SO 按架构分包/**三方 SDK 引入前称重**(体积+权限+隐私采集三查,eng-security 供应链同拍);
|
|
47
|
+
动态下发判据与合规边界:资源可动态,**代码动态下发看平台规则**(iOS 红线,见发布节)。
|
|
48
|
+
|
|
49
|
+
## 权限与隐私合规(国内上架生死线)
|
|
50
|
+
|
|
51
|
+
- 最小权限:用不到不申请;**用到的那一刻再弹**(首启轰炸=拒绝率与通报双高);拒绝后的降级路径要设计(无定位也能手选城市);
|
|
52
|
+
- **合规红线序**:首启隐私政策弹窗(明示收集清单)→用户同意→**才允许初始化任何采集 SDK**(未同意先采集=工信部通报高频第一名);
|
|
53
|
+
- 三方 SDK 合规清单:各 SDK 收集什么/隐私政策是否披露/版本是否在合规名单——SDK 升级也要复查;
|
|
54
|
+
- 自启动与关联启动收敛;个人信息处理登记(个保法):收集字段-用途-保存期限表;
|
|
55
|
+
- 双端隐私标注(Apple 隐私标签/App 权限说明)与实际行为一致(不一致=拒审)。
|
|
56
|
+
|
|
57
|
+
## 发布与灰度
|
|
58
|
+
|
|
59
|
+
- 双端通道:iOS TestFlight→分阶段发布(7 日曲线,可暂停);Android 国内多市场矩阵(各市场包管理+上架政策差异,渠道包统一构建产出);
|
|
60
|
+
- 强更/软更策略分级:安全漏洞与协议不兼容才强更(强更是核武器);版本支持窗口用数据定(最低系统版本看留存占比,砍版本前出影响数);
|
|
61
|
+
- **热修复判据**:iOS 禁热更代码(红线,违者下架风险);Android 补丁方案先过目标市场合规,只修崩溃级问题不带业务;
|
|
62
|
+
- 回滚现实:客户端发出去收不回——**灰度分阶段+服务端开关兜底**(高危功能后端可关)是唯一的"回滚"。
|
|
63
|
+
|
|
64
|
+
## 崩溃与监控
|
|
65
|
+
|
|
66
|
+
崩溃率红线进发布准出(参考 <0.1%,eng-quality 准出);**新增崩溃>存量崩溃**(新版本引入的优先);
|
|
67
|
+
符号表纪律:每次构建归档 dSYM/mapping(丢了=天书堆栈,发布流水线自动上传);
|
|
68
|
+
ANR/卡顿/启动耗时上报(eng-observability 端侧延伸);开屏必崩=P1 走 eng-ops(暂停放量+服务端开关止血)。
|
|
69
|
+
|
|
70
|
+
## 测试
|
|
71
|
+
|
|
72
|
+
单测:ViewModel/UseCase 纯逻辑层(架构分层的红利);
|
|
73
|
+
UI 测试:关键旅程(登录/核心任务/支付)双端各 ≤10 条;
|
|
74
|
+
真机矩阵:云真机覆盖 TOP 机型+最低支持版本;发布前 monkey/稳定性长跑;自动化工程细则载 **qa-mobile-automation**;
|
|
75
|
+
弱网与离线场景进用例(飞行模式切换/弱网工具)。
|
|
76
|
+
|
|
77
|
+
**作业包**:`references/store-compliance-checklist.md`(隐私合规红线序(同意后才初始化 SDK)/三方 SDK 登记表/发布自查与 48h 观察项)。
|
|
78
|
+
|
|
79
|
+
## 使用纪律
|
|
80
|
+
|
|
81
|
+
主线程红线评审必查;上架前合规自查单全过(隐私弹窗时序/权限清单/SDK 名单);
|
|
82
|
+
每版本三基线对照:启动耗时/包体积/崩溃率——**劣化当 bug 修**(eng-performance 回归防线同拍)。
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 移动端上架合规与发布自查单(dev-mobile 落笔件;政策会变,存疑处以当日官方文档为准)
|
|
2
|
+
|
|
3
|
+
## 1. 隐私合规红线序(工信部通报高频,逐项勾)
|
|
4
|
+
|
|
5
|
+
- [ ] **首启:隐私政策弹窗→用户同意→才初始化任何采集 SDK**(未同意先采集=通报第一名;冷启动代码走查确认初始化时序)
|
|
6
|
+
- [ ] 隐私政策链接可达,收集清单与实际一致(字段-用途-保存期限表:__)
|
|
7
|
+
- [ ] 权限最小化:逐项有业务理由;**用到那一刻再弹**;拒绝后降级路径可用(无定位可手选城市)
|
|
8
|
+
- [ ] 三方 SDK 合规清单(逐个登记):
|
|
9
|
+
|
|
10
|
+
| SDK | 版本 | 收集什么 | 隐私政策已披露 | 合规名单内 | 初始化时机(同意后?) |
|
|
11
|
+
|---|---|---|---|---|---|
|
|
12
|
+
|
|
13
|
+
- [ ] 自启动/关联启动收敛;后台无超范围采集
|
|
14
|
+
- [ ] 双端隐私标注(Apple 隐私标签/权限用途声明)与实际行为一致(不一致=拒审)
|
|
15
|
+
|
|
16
|
+
## 2. 发布前技术自查
|
|
17
|
+
|
|
18
|
+
- [ ] 三基线对照:启动耗时 __(基线 __)/包体积 __(基线 __)/崩溃率 __(红线 <0.1%)
|
|
19
|
+
- [ ] 符号表归档:dSYM/mapping 已上传(流水线自动;丢了=天书堆栈)
|
|
20
|
+
- [ ] 覆盖安装路径测过(老版本→新版本,数据迁移;覆盖崩=差评重灾)
|
|
21
|
+
- [ ] 强更/软更策略确认;服务端兼容窗口(老版本还能用 __ 天)
|
|
22
|
+
- [ ] 热修复合规:iOS 无代码热更;Android 补丁过目标市场规则
|
|
23
|
+
|
|
24
|
+
## 3. 双端通道检查
|
|
25
|
+
|
|
26
|
+
- iOS:□TestFlight 灰度 □分阶段发布(7 日曲线可暂停) □审核敏感项自查(虚拟支付/未披露权限)
|
|
27
|
+
- Android:□渠道包矩阵一致(统一构建产出) □各市场上架政策差异过一遍 □灰度比例 __
|
|
28
|
+
|
|
29
|
+
## 4. 上线后 48h 观察项
|
|
30
|
+
|
|
31
|
+
- [ ] 崩溃聚类(新增>存量优先;开屏必崩=P1 停放量+服务端开关止血)
|
|
32
|
+
- [ ] ANR/卡顿/启动耗时无劣化;核心旅程转化无异常
|
|
33
|
+
- [ ] 用户评价与客服通道盯守(隐性问题从这冒头)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-node
|
|
3
|
+
description: Node.js 服务端开发链(LTS 版本与包管理统一→NestJS/Fastify/Express 判据与 BFF 定位→事件循环阻塞定位→流与背压→内存泄漏四常客与容器内存对齐→优雅退出与健康检查→错误边界(操作性 vs 编程性)→pino 结构化日志→依赖安全与原型污染→PM2 vs 容器部署判据)。Node 后端/BFF 开发、接口卡顿、内存泄漏、OOMKilled 排查时载入。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Node.js 服务端开发链
|
|
8
|
+
|
|
9
|
+
eng-develop 的 Node 服务端孙链。前端工程见 dev-frontend;此处写服务端运行时特有判据。
|
|
10
|
+
|
|
11
|
+
## 基线
|
|
12
|
+
|
|
13
|
+
LTS 偶数版(奇数版不上生产);版本入库锁定(.nvmrc+engines+volta 任一,CI 同版);
|
|
14
|
+
包管理器一种到底,CI 用 `npm ci`/frozen-lockfile(锁文件漂移=构建不可重现);
|
|
15
|
+
TS 服务:开发 tsx/ts-node 直跑,**生产跑构建产物**(启动快+源码不上线);ESM/CJS 选定一种,混用互操作坑先认。
|
|
16
|
+
|
|
17
|
+
## 框架与定位判据
|
|
18
|
+
|
|
19
|
+
NestJS(团队大/要 DI 与模块化强约束/长期演进)/Fastify(性能敏感/轻量自组)/Express(生态惯性,注意中间件生态陈旧度);
|
|
20
|
+
**BFF 定位纪律**:聚合、裁剪、适配端差异——**业务事务不写在 BFF**(写了=第二个后端,两处业务逻辑漂移);
|
|
21
|
+
网关类需求(限流/鉴权/路由)交网关层,别在应用里手搓一半。
|
|
22
|
+
|
|
23
|
+
## 事件循环:单线程心智
|
|
24
|
+
|
|
25
|
+
- **一处阻塞=全部请求阻塞**。CPU 密集三出路:worker_threads(计算类)/子进程(隔离危险操作)/挪去别的服务(量大成规模);
|
|
26
|
+
- 隐形阻塞杀手:大 JSON.parse/stringify(几 MB 级就有感)、同步 fs/crypto 系列(带 Sync 后缀的都别在请求路径)、复杂正则灾难性回溯(ReDoS,eng-security);
|
|
27
|
+
- 定位:event loop delay/lag 指标常驻监控(eng-observability)+`--inspect` CPU profile 火焰图+长任务日志;
|
|
28
|
+
- 并发控制:**无界并发是自我 DoS**(`Promise.all` 一万个请求打下游),并发池限流(p-limit 思路)+下游超时。
|
|
29
|
+
|
|
30
|
+
## 流与背压
|
|
31
|
+
|
|
32
|
+
大文件/大结果集必须流式(整读进内存=OOM 预定);
|
|
33
|
+
`pipeline()` 替手动 pipe(错误传播与资源清理内建,手 pipe 漏 error 监听=进程崩);
|
|
34
|
+
**背压尊重**:write 返回 false 就停,等 drain 再写(不等=内存缓冲区无限涨);
|
|
35
|
+
HTTP 响应流式下发(CSV 导出/大列表)判据:>10MB 或生成慢的都该流。
|
|
36
|
+
|
|
37
|
+
## 内存:泄漏四常客与容器对齐
|
|
38
|
+
|
|
39
|
+
- 四常客:无上限缓存(Map 当缓存不设逐出→lru 化)/闭包长引用(回调持大对象)/事件监听未卸(EventEmitter 泄漏警告别 setMaxListeners 掩耳)/定时器未清(setInterval 无 clear);
|
|
40
|
+
- 定位:heapsnapshot 两次快照对比(泄漏对象增量一目了然);生产用 `--heapsnapshot-signal` 或诊断通道;
|
|
41
|
+
- **容器内存对齐**:`--max-old-space-size` 与容器 limit 匹配(留 25% 给堆外),默认堆上限≠容器限额——不对齐=莫名 OOMKilled(K8s 事件里才看得到,应用日志无迹);
|
|
42
|
+
- Buffer 属堆外,大量 Buffer 场景堆不大也能超容器限额。
|
|
43
|
+
|
|
44
|
+
## 进程生命周期与部署
|
|
45
|
+
|
|
46
|
+
- **优雅退出序**:收 SIGTERM → 停接新请求(server.close)→ 在途请求完成 → 关连接池/MQ 消费 → 退出;超时兜底强杀(30s);K8s preStop+terminationGracePeriod 配合;
|
|
47
|
+
- 健康检查两级:liveness 简单自检(别查依赖,eng-infra 探针判据)/readiness 查依赖;
|
|
48
|
+
- 部署判据:**容器/K8s 下单进程副本交编排,别再 PM2 cluster**(两层管理打架);裸机多核才用 PM2 cluster;
|
|
49
|
+
- 崩溃哲学:uncaughtException/unhandledRejection **必须挂**——记日志+优雅退出,不硬扛(状态已不可信);进程管理器/编排负责拉起。
|
|
50
|
+
|
|
51
|
+
## 错误边界
|
|
52
|
+
|
|
53
|
+
操作性错误(下游超时/校验失败)= 预期内,分类处理+重试退避;编程性错误(undefined 调用)= bug,快崩快修;
|
|
54
|
+
async 错误统一到框架错误中间件(Express 的 async 包装/Fastify 内建);
|
|
55
|
+
错误响应统一结构+traceId(eng-observability);**吞错(catch 后空过)评审红线**(eng-develop 通则)。
|
|
56
|
+
|
|
57
|
+
## 日志
|
|
58
|
+
|
|
59
|
+
pino 结构化 JSON(console.log 上生产=不可检索+性能差);
|
|
60
|
+
requestId/traceId 用 AsyncLocalStorage 贯穿(手传参数版本必漏);
|
|
61
|
+
日志分级与敏感信息纪律承 eng-observability。
|
|
62
|
+
|
|
63
|
+
## 依赖与安全
|
|
64
|
+
|
|
65
|
+
audit 门禁分级(eng-security SCA SLA);锁文件必提交;
|
|
66
|
+
**安装脚本风险**:第三方包 postinstall 可执行任意代码,私服白名单+`--ignore-scripts` 判据(开了要处理需编译依赖);
|
|
67
|
+
原型污染:合并/克隆工具对外部输入慎用(`__proto__` 键),入口统一 schema 校验(zod/ajv)——**校验过的数据才进业务**;
|
|
68
|
+
eval/new Function 禁;child_process 拼接命令禁(参数数组化,eng-security 命令注入)。
|
|
69
|
+
|
|
70
|
+
## 测试
|
|
71
|
+
|
|
72
|
+
node:test 或 vitest;接口级 supertest(起内存 server 全链路);
|
|
73
|
+
时间与随机注入;外部服务 mock 在 HTTP 层(nock 思路)而非函数层(更接近真实);
|
|
74
|
+
DB 集成测试真库容器(eng-quality 同则)。
|
|
75
|
+
|
|
76
|
+
**作业包**:`scripts/node-triage.sh`(cgroup 内存对齐(OOMKilled 头号根因)/句柄/CLOSE_WAIT 归属/关键环境一键初判)。
|
|
77
|
+
|
|
78
|
+
## 使用纪律
|
|
79
|
+
|
|
80
|
+
请求路径禁同步 IO 与无界并发(评审必查);压测定容量再上线(eng-performance);
|
|
81
|
+
每次 OOM/卡死事故回写:泄漏模式或阻塞源入本链清单;
|
|
82
|
+
BFF 的接口契约与前端同源(api-design 生成类型,dev-frontend 同拍)。
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Node 进程一键排障(dev-node 内存对齐/句柄/连接泄漏的采集与初判)。只读,POSIX sh,降级友好。
|
|
3
|
+
# 用法: sh node-triage.sh <PID>
|
|
4
|
+
# 覆盖: 容器内存对齐(--max-old-space-size vs cgroup,OOMKilled 头号根因)/RSS 与句柄水位/
|
|
5
|
+
# CLOSE_WAIT 归属/线程数/关键环境变量。堆内 profile 走 --inspect/heapsnapshot(链内画像节)。
|
|
6
|
+
PID="$1"
|
|
7
|
+
[ -z "$PID" ] && { echo "用法: node-triage.sh <PID>"; exit 2; }
|
|
8
|
+
kill -0 "$PID" 2>/dev/null || { echo "[错误] 进程 $PID 不存在或无权限"; exit 2; }
|
|
9
|
+
have() { command -v "$1" >/dev/null 2>&1; }
|
|
10
|
+
Y=""
|
|
11
|
+
yel() { Y="$Y
|
|
12
|
+
[!] $1"; }
|
|
13
|
+
|
|
14
|
+
echo "==== Node 排障 PID=$PID ===="
|
|
15
|
+
ps -o pid,user,etime,rss,args -p "$PID" 2>/dev/null | head -2
|
|
16
|
+
RSS_KB=$(ps -o rss= -p "$PID" 2>/dev/null | tr -d ' ')
|
|
17
|
+
[ -n "$RSS_KB" ] && echo "RSS: $((RSS_KB / 1024))MB"
|
|
18
|
+
|
|
19
|
+
echo ""
|
|
20
|
+
echo "---- 内存对齐(OOMKilled 第一嫌疑) ----"
|
|
21
|
+
ARGS=$(ps -o args= -p "$PID" 2>/dev/null)
|
|
22
|
+
MOS=$(echo "$ARGS" | grep -oE 'max-old-space-size=[0-9]+' | head -1 | cut -d= -f2)
|
|
23
|
+
[ -z "$MOS" ] && [ -r "/proc/$PID/environ" ] && \
|
|
24
|
+
MOS=$(tr '\0' '\n' < "/proc/$PID/environ" 2>/dev/null | grep -oE 'max-old-space-size=[0-9]+' | head -1 | cut -d= -f2)
|
|
25
|
+
echo "--max-old-space-size: ${MOS:-未设置(默认堆上限≠容器限额)}"
|
|
26
|
+
CG=""
|
|
27
|
+
for f in /sys/fs/cgroup/memory.max /sys/fs/cgroup/memory/memory.limit_in_bytes; do
|
|
28
|
+
[ -r "$f" ] && CG=$(cat "$f") && break
|
|
29
|
+
done
|
|
30
|
+
if [ -n "$CG" ] && [ "$CG" != "max" ]; then
|
|
31
|
+
CGMB=$((CG / 1048576))
|
|
32
|
+
echo "cgroup 内存上限: ${CGMB}MB"
|
|
33
|
+
if [ -z "$MOS" ]; then
|
|
34
|
+
yel "容器有限额但未设 max-old-space-size —— 建议设为 limit 的 75%(≈$((CGMB * 3 / 4))MB,留堆外与 Buffer)"
|
|
35
|
+
elif [ "$MOS" -gt $((CGMB * 9 / 10)) ] 2>/dev/null; then
|
|
36
|
+
yel "max-old-space-size(${MOS}MB) 逼近 cgroup(${CGMB}MB) —— 堆外+Buffer 无余量,OOMKilled 风险"
|
|
37
|
+
fi
|
|
38
|
+
[ -n "$RSS_KB" ] && [ $((RSS_KB / 1024)) -gt $((CGMB * 85 / 100)) ] && yel "RSS 已达 cgroup 的 85%+ —— 快照对比找泄漏四常客"
|
|
39
|
+
else
|
|
40
|
+
echo "cgroup: 未检出限额(裸机/非容器)"
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
echo ""
|
|
44
|
+
echo "---- 句柄与连接 ----"
|
|
45
|
+
if [ -d "/proc/$PID/fd" ]; then
|
|
46
|
+
FD=$(ls "/proc/$PID/fd" 2>/dev/null | wc -l | tr -d ' ')
|
|
47
|
+
LIM=$(grep -i 'Max open files' "/proc/$PID/limits" 2>/dev/null | awk '{print $4}')
|
|
48
|
+
echo "打开句柄: $FD / 上限 ${LIM:-?}"
|
|
49
|
+
[ -n "$LIM" ] && [ "$LIM" != "unlimited" ] && [ "$FD" -gt $((LIM * 7 / 10)) ] 2>/dev/null && yel "句柄 >70% 上限 —— 泄漏四常客+流未关排查"
|
|
50
|
+
elif have lsof; then
|
|
51
|
+
FD=$(lsof -p "$PID" 2>/dev/null | wc -l | tr -d ' ')
|
|
52
|
+
echo "打开句柄(lsof 估计): $FD"
|
|
53
|
+
fi
|
|
54
|
+
if have ss; then
|
|
55
|
+
CW=$(ss -tanp 2>/dev/null | grep "pid=$PID" | grep -c CLOSE-WAIT)
|
|
56
|
+
EST=$(ss -tanp 2>/dev/null | grep "pid=$PID" | grep -c ESTAB)
|
|
57
|
+
echo "本进程连接: ESTAB=$EST CLOSE_WAIT=$CW"
|
|
58
|
+
[ "$CW" -gt 50 ] 2>/dev/null && yel "CLOSE_WAIT=$CW —— 响应体/连接未消费关闭(HTTP client body 必须消费或销毁)"
|
|
59
|
+
fi
|
|
60
|
+
if [ -r "/proc/$PID/status" ]; then
|
|
61
|
+
TH=$(grep '^Threads' "/proc/$PID/status" | awk '{print $2}')
|
|
62
|
+
echo "线程数: $TH (libuv 线程池默认 4,UV_THREADPOOL_SIZE 可调;线程暴涨查 worker_threads 泄漏)"
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
echo ""
|
|
66
|
+
echo "---- 关键环境 ----"
|
|
67
|
+
if [ -r "/proc/$PID/environ" ]; then
|
|
68
|
+
tr '\0' '\n' < "/proc/$PID/environ" 2>/dev/null | grep -E '^(NODE_ENV|NODE_OPTIONS|UV_THREADPOOL_SIZE)=' | sed 's/^/ /'
|
|
69
|
+
tr '\0' '\n' < "/proc/$PID/environ" 2>/dev/null | grep -q '^NODE_ENV=production' || yel "NODE_ENV 非 production —— 部分框架走开发路径(性能与缓存差一截)"
|
|
70
|
+
else
|
|
71
|
+
echo " (/proc 不可读,环境变量跳过 —— macOS/权限)"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
echo ""
|
|
75
|
+
echo "==== 初判 ===="
|
|
76
|
+
if [ -n "$Y" ]; then echo "待处理:$Y"; else echo "未见系统侧明显异常 —— 事件循环阻塞/堆内泄漏走 --inspect profile 与 heapsnapshot(dev-node 画像节)"; fi
|
|
77
|
+
echo "深入三招: event loop delay 指标 / CPU profile 火焰图 / 两次 heapsnapshot 对比。"
|
|
78
|
+
exit 0
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-php
|
|
3
|
+
description: PHP 技术开发链(PHP 8 现代化(严格类型/枚举/readonly)→5.x→8 迁移路径与 rector→Composer 治理→Laravel/ThinkPHP/Symfony 判据→Eloquent N+1→FPM 调参公式与慢日志→OPcache/JIT 判据→安全 TOP(注入/反序列化/上传/弱比较)→PHPUnit→Swoole 常驻心智切换→部署重载)。PHP 开发、老系统维护升级、FPM 性能、安全整改时载入。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# PHP 技术开发链
|
|
8
|
+
|
|
9
|
+
eng-develop 的 PHP 孙链。通则承 eng-develop,此处只写 PHP 特有判据。国内存量 PHP 系统多为 5.x/7.x 老项目,迁移与安全是本链两大重心。
|
|
10
|
+
|
|
11
|
+
## 版本与现代化
|
|
12
|
+
|
|
13
|
+
- 新代码 8.1+ 起步(枚举/readonly/纤程/never);**新文件 `declare(strict_types=1)` 纪律**(弱类型自动转换是 PHP bug 温床之首);
|
|
14
|
+
- 类型全覆盖渐进:参数/返回/属性类型逐步补(phpstan/psalm 静态分析分级推进,level 逐档提);
|
|
15
|
+
- **5.x→8 迁移路径**:先上静态分析摸家底 → rector 自动化改写过渡到 7.4 → 高危变更表人工过(引用传参语义/花括号字符串下标移除/魔术引号与 mysql_ 系残留/create_function/each)→ 8.x(命名参数与内部函数签名收紧)——分模块灰度,全量回归护航(refactor-safely 特征测试先行);
|
|
16
|
+
- ext 兼容清单先查(老扩展无 8 版=改造或替换,迁移排期大头常在这)。
|
|
17
|
+
|
|
18
|
+
## Composer 治理
|
|
19
|
+
|
|
20
|
+
锁文件必提交;`config.platform.php` 锁定目标运行时版本(本地 8.3 装出生产 8.1 跑不了的包=经典);
|
|
21
|
+
autoload PSR-4,禁 require 手串文件;
|
|
22
|
+
**`composer update` 只许带包名**(裸 update=全量开盲盒,升级走 dependency-upgrade);
|
|
23
|
+
私服/国内镜像统一(dev-toolchain);abandoned 包季度巡检(PHP 生态弃坑率高)。
|
|
24
|
+
|
|
25
|
+
## 框架判据
|
|
26
|
+
|
|
27
|
+
Laravel(生态最全/招聘面广;魔法多,**门面与魔术方法让 IDE 与静态分析打折**,ide-helper 类工具补);
|
|
28
|
+
ThinkPHP(国内存量大/中文文档;版本代差大,3.x 与 6+ 是两个世界,老版本安全补丁要盯);
|
|
29
|
+
Symfony 组件化(自建/改造老项目的正路:不换框架,先引组件替手写轮子);
|
|
30
|
+
**存量框架不折腾**(换框架=重写,按 eng-research 退出成本评估),新服务再选型。
|
|
31
|
+
|
|
32
|
+
## 工程结构与 ORM
|
|
33
|
+
|
|
34
|
+
Controller 薄;输入验证收口(FormRequest/验证器,**$_GET/$_POST 裸用评审拦**);服务层持事务边界;
|
|
35
|
+
**Eloquent N+1 专项**:列表页 `with()` 预加载;debugbar/查询日志盯单请求查询数(>20 条即嫌疑);`chunk/cursor` 处理大结果集(all() 整取=内存峰值);
|
|
36
|
+
生成 SQL 抽查 EXPLAIN(eng-database ORM 不免检)。
|
|
37
|
+
|
|
38
|
+
## PHP-FPM 调参
|
|
39
|
+
|
|
40
|
+
- pm 模式:`dynamic` 默认/`static` 高负载稳定(省进程管理开销);
|
|
41
|
+
- **max_children 公式**:可用内存 ÷ 单进程峰值内存(实测 RSS,别拍脑袋)——设大了 OOM,设小了 502/排队;
|
|
42
|
+
- 必开三件:`request_slowlog_timeout`+slowlog(慢请求自动打栈,定位神器)/`pm.max_requests`(防泄漏兜底重启)/`pm.status_path`(池状态监控入 eng-observability);
|
|
43
|
+
- 超时链对齐:nginx `fastcgi_read_timeout` ≥ PHP `max_execution_time`,不对齐=504 与半执行。
|
|
44
|
+
|
|
45
|
+
## OPcache / JIT
|
|
46
|
+
|
|
47
|
+
**OPcache 生产必开**(字节码缓存,数倍差距);容量与命中率监控(满了=静默性能悬崖);
|
|
48
|
+
`validate_timestamps=0` 生产关校验(发布时显式重载,见部署节);
|
|
49
|
+
preload 判据(框架核心类常驻,8.x 收益可测再开);
|
|
50
|
+
JIT:CPU 密集计算才有感,常规 Web IO 型收益小——**别为 JIT 折腾,先修 N+1**。
|
|
51
|
+
|
|
52
|
+
## 安全 TOP(PHP 重灾区专项,总则承 eng-security)
|
|
53
|
+
|
|
54
|
+
SQL 注入:PDO 预处理参数化(拼接=红线);ORM 的 `whereRaw`/原生片段照查;
|
|
55
|
+
**反序列化:`unserialize()` 外部输入=RCE 级危险**(POP 链),一律 JSON 替代;`phar://` 触发面(文件函数收到用户可控路径要过滤协议);
|
|
56
|
+
文件上传:三验(白名单扩展名+MIME+内容魔数)+存储出 webroot+随机名+禁执行权限;
|
|
57
|
+
文件包含:用户输入进 include/require=红线(模板白名单映射);
|
|
58
|
+
**弱比较**:`==` 的魔法(`"0e123"=="0e456"` 为真/`0=="a"` 历史差异)——比较用 `===`;密码一律 `password_hash/password_verify`,token 比较 `hash_equals`(防时序);
|
|
59
|
+
XSS:模板引擎自动转义确认开启({!! !!} 与 raw 输出评审必查);
|
|
60
|
+
配置红线:`display_errors=Off` 生产铁律(错误回显=信息泄露),错误进日志(eng-observability)。
|
|
61
|
+
|
|
62
|
+
## 测试
|
|
63
|
+
|
|
64
|
+
PHPUnit;数据库测试事务回滚 trait(RefreshDatabase 类机制,注意速度选内存库要认差异——eng-quality 真库判据);
|
|
65
|
+
HTTP 功能测试(框架内建 `$this->post()` 断言链);
|
|
66
|
+
**老代码先补特征测试再动**(锁住现状行为,refactor-safely)——没有测试的重构叫赌博。
|
|
67
|
+
|
|
68
|
+
## 常驻内存判据(Swoole/RoadRunner/FrankenPHP)
|
|
69
|
+
|
|
70
|
+
上的判据:长连接(IM/推送)/高并发低延迟/队列消费常驻——常规 CRUD 上 FPM 足够;
|
|
71
|
+
**心智切换认账**:FPM 的"请求即世界"失效——全局/静态变量跨请求污染(单例带用户态=窜数据事故)、连接要池化、内存泄漏会累积(监控+定期优雅重启)、`die/exit` 不可用;
|
|
72
|
+
框架要选常驻兼容版本;能力不足时别硬上(排障工具与人才储备都比 FPM 少)。
|
|
73
|
+
|
|
74
|
+
## 部署
|
|
75
|
+
|
|
76
|
+
FPM+nginx 基线;容器化:fpm+nginx 双容器(职责清)或 supervisord 单容器(简单)判据;
|
|
77
|
+
**发布重载序**:新代码就位 → `opcache_reset`/优雅 reload FPM(USR2)→ 验证——validate_timestamps=0 时忘重载=新代码不生效"灵异事件";
|
|
78
|
+
定时任务收敛(crontab 入库管理或调度中心,散落各机=幽灵任务)。
|
|
79
|
+
|
|
80
|
+
**作业包**:`scripts/fpm-calc.py`(max_children 内存公式+目标 QPS 吞吐核对+必开三件与超时链提醒)。
|
|
81
|
+
|
|
82
|
+
## 使用纪律
|
|
83
|
+
|
|
84
|
+
strict_types 新文件全覆盖;静态分析 level 只升不降;
|
|
85
|
+
`==`/裸超全局/unserialize 评审三查;每次安全整改回写本链 TOP 清单;
|
|
86
|
+
慢日志月度 TOP 治理(与 sql-tuning 联动)。
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# PHP-FPM 调参计算器(dev-php max_children 公式的可执行版)。python3 stdlib,零依赖。
|
|
3
|
+
# 用法:
|
|
4
|
+
# python3 fpm-calc.py --mem-total-mb 8192 --proc-mem-mb 64 [--reserve-mb 1024] [--avg-req-ms 80 --target-qps 300]
|
|
5
|
+
# python3 fpm-calc.py --selftest
|
|
6
|
+
# proc-mem-mb 用实测 RSS(别拍脑袋): ps -o rss= -C php-fpm | awk '{s+=$1;n++} END{print s/n/1024}'
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def calc(a):
|
|
12
|
+
avail = a.mem_total_mb - a.reserve_mb
|
|
13
|
+
if avail <= 0 or a.proc_mem_mb <= 0:
|
|
14
|
+
print("[错误] 可用内存或单进程内存不合法")
|
|
15
|
+
return 2
|
|
16
|
+
mc = int(avail / a.proc_mem_mb)
|
|
17
|
+
print(f"max_children = (总内存{a.mem_total_mb}MB - 预留{a.reserve_mb}MB[OS/DB/缓存]) ÷ 单进程峰值{a.proc_mem_mb}MB = {mc}")
|
|
18
|
+
print(f" 配套建议: pm=dynamic 时 start={max(mc // 4, 2)} min_spare={max(mc // 8, 2)} max_spare={max(mc // 2, 4)};高负载稳定场景 pm=static")
|
|
19
|
+
if a.avg_req_ms and a.target_qps:
|
|
20
|
+
need = a.target_qps * a.avg_req_ms / 1000
|
|
21
|
+
print(f"吞吐核对: 目标 {a.target_qps} QPS × 平均 {a.avg_req_ms}ms = 需并发 worker ≈ {need:.0f}")
|
|
22
|
+
if need > mc:
|
|
23
|
+
print(f" [红] 需要 {need:.0f} > 内存上限 {mc} —— 内存不够撑目标 QPS:降单进程内存(查泄漏/大数组)、加机器、或上缓存降 QPS 到库")
|
|
24
|
+
else:
|
|
25
|
+
print(f" 内存上限 {mc} 足够(余量 {(mc - need) * 100 / mc:.0f}%);瓶颈更可能在下游(N+1/慢 SQL,先修那个)")
|
|
26
|
+
print("必开三件核对: request_slowlog_timeout+slowlog / pm.max_requests(防泄漏兜底) / pm.status_path(监控);")
|
|
27
|
+
print("超时链对齐: nginx fastcgi_read_timeout ≥ PHP max_execution_time(不对齐=504 与半执行,dev-php)。")
|
|
28
|
+
return 0
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def selftest():
|
|
32
|
+
ns = argparse.Namespace
|
|
33
|
+
assert calc(ns(mem_total_mb=8192, proc_mem_mb=64, reserve_mb=1024, avg_req_ms=80, target_qps=300)) == 0
|
|
34
|
+
assert calc(ns(mem_total_mb=2048, proc_mem_mb=128, reserve_mb=512, avg_req_ms=200, target_qps=500)) == 0 # 触发红灯路径
|
|
35
|
+
print("\nselftest ok")
|
|
36
|
+
return 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
if "--selftest" in sys.argv:
|
|
41
|
+
sys.exit(selftest())
|
|
42
|
+
p = argparse.ArgumentParser(description="PHP-FPM max_children 计算")
|
|
43
|
+
p.add_argument("--mem-total-mb", type=float, required=True)
|
|
44
|
+
p.add_argument("--proc-mem-mb", type=float, required=True)
|
|
45
|
+
p.add_argument("--reserve-mb", type=float, default=1024)
|
|
46
|
+
p.add_argument("--avg-req-ms", type=float)
|
|
47
|
+
p.add_argument("--target-qps", type=float)
|
|
48
|
+
sys.exit(calc(p.parse_args()))
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dev-python
|
|
3
|
+
description: Python 技术开发链(3.10+ 与 uv/venv 环境隔离→pyproject 单一事实源与依赖锁定→类型注解渐进 mypy→pytest fixture/参数化/mock 边界→asyncio 判据与阻塞排查→pandas 内存与向量化→cProfile/py-spy 画像→打包发布判据→常见坑 TOP→脚本工程化四件套)。Python 开发、环境依赖混乱、数据处理性能、脚本上生产时载入。
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Python 技术开发链
|
|
8
|
+
|
|
9
|
+
eng-develop 的 Python 孙链。通则承 eng-develop,此处只写 Python 特有判据。
|
|
10
|
+
|
|
11
|
+
## 版本与环境
|
|
12
|
+
|
|
13
|
+
- 3.10+ 起步(结构化模式匹配/精确报错行);3.12+ 性能红利可观;
|
|
14
|
+
- **每项目独立环境**:uv 优先(解析快、锁一致、代 pip/venv/pipx 多角色),venv+pip 兜底;**系统 Python 永不装包**(apt/brew 的 Python 是系统件,不是你的游乐场);
|
|
15
|
+
- 版本声明入库:`requires-python` + `.python-version`(工具链锁,dev-toolchain 三锁之一);
|
|
16
|
+
- 依赖两层分离:直接依赖(pyproject 声明,range 宽松)与锁定文件(uv.lock/requirements.txt 精确,**必提交**);更新集中走 dependency-upgrade。
|
|
17
|
+
|
|
18
|
+
## 工程结构
|
|
19
|
+
|
|
20
|
+
- **src 布局**(src/pkg/ 而非根目录平铺):防"测试import到了本地目录而非安装包"的经典假绿;
|
|
21
|
+
- pyproject.toml 单一事实源:依赖/构建/工具配置(ruff/mypy/pytest)归一,告别 setup.py+cfg+ini 三分天下;
|
|
22
|
+
- 入口纪律:库暴露 `__init__` 公共面;应用用 `if __name__ == "__main__":` + console_scripts;
|
|
23
|
+
- **脚本工程化四件套**(脚本上生产的底线):argparse 参数(禁硬编码路径)/logging 替 print(可调级别)/明确退出码(0 成功非 0 失败,调度系统靠它判断)/异常兜底(裸栈滚屏≠错误处理)。
|
|
24
|
+
|
|
25
|
+
## 类型注解渐进
|
|
26
|
+
|
|
27
|
+
新代码必注(函数签名起步);核心模块回补;mypy 分模块渐进 strict(一步到位=劝退);
|
|
28
|
+
高频工具:`Optional` 显式(隐式 None 是 bug 温床)/`TypedDict`(接口字典结构化)/`Protocol`(鸭子类型正名,免继承耦合)/dataclass 或 pydantic(边界校验判据:外部输入用 pydantic 校验,内部传递 dataclass 够用)。
|
|
29
|
+
|
|
30
|
+
## 常见坑 TOP(评审自查单)
|
|
31
|
+
|
|
32
|
+
可变默认参数 `def f(x=[])`(共享一个列表,用 None 哨兵);
|
|
33
|
+
闭包晚绑定(循环里 lambda 全捕获最后值,默认参数固化 `lambda i=i:`);
|
|
34
|
+
`is` vs `==`(is 只用于 None/单例;小整数缓存的 is 巧合别依赖);
|
|
35
|
+
浮点:钱用 Decimal(字符串构造),0.1+0.2!=0.3;
|
|
36
|
+
**GIL 认知**:线程只救 IO 密集;CPU 密集用多进程或 numpy/polars(C 层释放 GIL);3.13+ free-threaded 仍属评估期;
|
|
37
|
+
循环 import:分层修架构或函数内延迟导入(后者是止痛不是治病);
|
|
38
|
+
编码:`open()` 显式 `encoding="utf-8"`(Windows 默认 GBK 惨案高发);
|
|
39
|
+
时区:naive datetime 禁上生产,`datetime.now(timezone.utc)` 起步;
|
|
40
|
+
异常:禁裸 `except:`(连 KeyboardInterrupt 都吞),`except Exception` 且记日志带栈(`logger.exception`);
|
|
41
|
+
路径:pathlib 替字符串拼接;`os.path.join` 遇绝对路径会"吞前缀"。
|
|
42
|
+
|
|
43
|
+
## pytest 体系
|
|
44
|
+
|
|
45
|
+
- fixture 金字塔:conftest.py 分层放(就近原则),作用域明确(function 默认,session 级共享资源);
|
|
46
|
+
- `@pytest.mark.parametrize` 铺边界(eng-quality 三点法);
|
|
47
|
+
- **mock 打补丁位置=使用处不是定义处**(`patch("app.service.requests")` 而非 `patch("requests")`——高频翻车点);mock 边界纪律承 eng-quality;
|
|
48
|
+
- 慢测标记分离(`-m "not slow"` 日常,全量进 CI);随机与时间注入固定(freezegun/固定 seed)——**结果可复算**;
|
|
49
|
+
- 覆盖率下限进 CI(下限告警,不冲高分)。
|
|
50
|
+
|
|
51
|
+
## asyncio 判据
|
|
52
|
+
|
|
53
|
+
- 上 async 的判据:高并发 IO(爬虫/网关/长连接);CPU 密集与低并发脚本别凑热闹;
|
|
54
|
+
- **同步库混进事件循环=全场卡死**(requests 混在 async 里),用 aiohttp/httpx(async 客户端);存量同步调用 `run_in_executor` 包;
|
|
55
|
+
- 超时纪律:每个 await 外部调用有 timeout(`asyncio.timeout` 上下文);
|
|
56
|
+
- 并发结构化:`TaskGroup`(3.11+)统一收错,替代裸 `create_task` 散养(散养任务的异常无人认领);
|
|
57
|
+
- 阻塞排查:debug 模式 `PYTHONASYNCIODEBUG=1` 报慢回调;事件循环卡顿监控。
|
|
58
|
+
|
|
59
|
+
## pandas 内存与性能
|
|
60
|
+
|
|
61
|
+
读取即瘦身:`usecols` 只要所需列、`dtype` 显式(默认 object 吃内存)、低基数列转 `category`;
|
|
62
|
+
大文件 `chunksize` 分块或直接上 polars/duckdb(**数据>内存 1/3 就该换引擎**,duckdb 直查 parquet/csv 常常免加载);
|
|
63
|
+
向量化替 `iterrows`(百倍差距);链式赋值警告的正解是 `.loc[]` 单步定位;
|
|
64
|
+
中间结果落盘 parquet(重跑从断点起,eng-data-platform 中间表纪律同拍)。
|
|
65
|
+
|
|
66
|
+
## 画像与排障
|
|
67
|
+
|
|
68
|
+
cProfile 找热点函数(配 snakeviz 可视化);**py-spy 生产可用**(无侵入采样:`py-spy top` 实时/`py-spy dump` 卡死现场栈——进程假死第一招);
|
|
69
|
+
行级瓶颈 line_profiler;内存 tracemalloc(增量快照对比找泄漏)。
|
|
70
|
+
|
|
71
|
+
## 打包与发布
|
|
72
|
+
|
|
73
|
+
库:wheel 构建发私服;应用:**容器优先**(环境锁死);单文件 PyInstaller 判据(无 Python 环境的分发场景)+坑先认(杀软误报/启动解压慢/隐藏导入手工补);
|
|
74
|
+
入口脚本用 console_scripts 而非"python 某路径"(路径耦合)。
|
|
75
|
+
|
|
76
|
+
**作业包**:`scripts/venv-doctor.sh`(解释器身份/venv 状态/镜像源/锁文件纪律/同名遮蔽等坑位一键体检)。
|
|
77
|
+
|
|
78
|
+
## 使用纪律
|
|
79
|
+
|
|
80
|
+
无锁定文件不部署;脚本三无(无日志/无参数/无退出码)不上生产;
|
|
81
|
+
数据处理固定 seed+版本锁定保证可复算;每次环境事故回写:锁文件纪律或镜像基线(dev-toolchain)。
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Python 环境医生(dev-python"环境依赖混乱"的一键诊断)。只读,零依赖,POSIX sh。
|
|
3
|
+
# 用法: sh venv-doctor.sh [项目目录] # 缺省当前目录
|
|
4
|
+
# 诊断: 解释器身份/venv 状态/镜像源配置/锁文件纪律/版本声明一致性/依赖冲突/常见坑位。
|
|
5
|
+
DIR="${1:-.}"
|
|
6
|
+
cd "$DIR" 2>/dev/null || { echo "[错误] 目录不存在: $DIR"; exit 2; }
|
|
7
|
+
have() { command -v "$1" >/dev/null 2>&1; }
|
|
8
|
+
Y=""
|
|
9
|
+
yel() { Y="$Y
|
|
10
|
+
[!] $1"; }
|
|
11
|
+
|
|
12
|
+
echo "==== Python 环境体检 ($(pwd)) ===="
|
|
13
|
+
|
|
14
|
+
echo "---- 解释器身份 ----"
|
|
15
|
+
for py in python3 python; do
|
|
16
|
+
if have "$py"; then
|
|
17
|
+
echo "$py → $(command -v $py) ($($py -V 2>&1))"
|
|
18
|
+
fi
|
|
19
|
+
done
|
|
20
|
+
have python3 || have python || { echo "[红] 无 python —— 离线环境从离线仓装(env-offline)"; exit 3; }
|
|
21
|
+
PY=$(have python3 && echo python3 || echo python)
|
|
22
|
+
|
|
23
|
+
echo ""
|
|
24
|
+
echo "---- venv 状态 ----"
|
|
25
|
+
INV=$($PY -c "import sys; print('venv' if sys.prefix != getattr(sys,'base_prefix',sys.prefix) else 'system')" 2>/dev/null)
|
|
26
|
+
if [ "$INV" = "venv" ]; then
|
|
27
|
+
echo "当前解释器在虚拟环境: $($PY -c 'import sys; print(sys.prefix)')"
|
|
28
|
+
else
|
|
29
|
+
echo "当前解释器 = 系统 Python"
|
|
30
|
+
[ -n "$VIRTUAL_ENV" ] && yel "VIRTUAL_ENV=$VIRTUAL_ENV 已设但解释器不是它 —— PATH 顺序问题(激活没生效/shell 缓存 hash -r)"
|
|
31
|
+
[ -d .venv ] && yel "项目有 .venv/ 但未激活 —— 你可能正把包装进系统 Python(系统 Python 永不装包纪律)"
|
|
32
|
+
fi
|
|
33
|
+
echo "site-packages: $($PY -c 'import site; print(site.getsitepackages()[0] if site.getsitepackages() else site.getusersitepackages())' 2>/dev/null)"
|
|
34
|
+
|
|
35
|
+
echo ""
|
|
36
|
+
echo "---- 版本声明一致性(dev-toolchain 三锁) ----"
|
|
37
|
+
DECL=""
|
|
38
|
+
[ -f .python-version ] && DECL=$(cat .python-version | head -1) && echo ".python-version: $DECL"
|
|
39
|
+
[ -f pyproject.toml ] && grep -E 'requires-python' pyproject.toml | head -1 | sed 's/^/pyproject: /'
|
|
40
|
+
RUN=$($PY -c 'import sys; print("%d.%d"%sys.version_info[:2])')
|
|
41
|
+
echo "运行版本: $RUN"
|
|
42
|
+
[ -n "$DECL" ] && case "$DECL" in "$RUN"*) : ;; *) yel "运行版本 $RUN 与 .python-version($DECL) 不一致";; esac
|
|
43
|
+
|
|
44
|
+
echo ""
|
|
45
|
+
echo "---- 依赖与锁文件 ----"
|
|
46
|
+
LOCK=""
|
|
47
|
+
for f in uv.lock poetry.lock requirements.txt requirements.lock Pipfile.lock; do
|
|
48
|
+
[ -f "$f" ] && LOCK="$LOCK $f"
|
|
49
|
+
done
|
|
50
|
+
if [ -n "$LOCK" ]; then echo "锁文件:$LOCK"; else yel "无锁文件 —— 无锁定文件不部署(dev-python 纪律)"; fi
|
|
51
|
+
[ -f requirements.txt ] && grep -cE '==' requirements.txt >/dev/null 2>&1 && {
|
|
52
|
+
UNPINNED=$(grep -vcE '^(#|$|.*==|.*@|-r )' requirements.txt)
|
|
53
|
+
[ "$UNPINNED" -gt 0 ] 2>/dev/null && yel "requirements.txt 有 $UNPINNED 行未钉版本(应用要精确锁定)"
|
|
54
|
+
}
|
|
55
|
+
if have uv; then echo "uv: $(uv --version 2>/dev/null)"; fi
|
|
56
|
+
echo "pip 源配置:"
|
|
57
|
+
$PY -m pip config list 2>/dev/null | grep -E 'index-url|trusted' | sed 's/^/ /' || echo " (默认官方源;内网配私服/镜像,dev-toolchain)"
|
|
58
|
+
|
|
59
|
+
echo ""
|
|
60
|
+
echo "---- 依赖健康(pip check) ----"
|
|
61
|
+
CHK=$($PY -m pip check 2>&1 | head -5)
|
|
62
|
+
if echo "$CHK" | grep -qiE 'no broken|^$'; then echo " 无冲突"; else echo "$CHK" | sed 's/^/ /'; yel "存在依赖冲突(pip check 有输出)"; fi
|
|
63
|
+
|
|
64
|
+
echo ""
|
|
65
|
+
echo "---- 常见坑位扫描 ----"
|
|
66
|
+
[ -f setup.py ] && [ -f pyproject.toml ] && echo " setup.py 与 pyproject 并存(逐步归一到 pyproject 单一事实源)"
|
|
67
|
+
ls *.py 2>/dev/null | grep -qE '^(json|csv|logging|token|types|email)\.py$' && yel "项目根有与标准库同名的 .py(json.py 等)—— 遮蔽标准库的经典事故"
|
|
68
|
+
[ -d src ] || { ls *.py >/dev/null 2>&1 && [ -f pyproject.toml ] && echo " 非 src 布局(可用;新库建议 src/ 防'测到本地目录'假绿)"; }
|
|
69
|
+
[ -n "$PYTHONPATH" ] && yel "PYTHONPATH=$PYTHONPATH 已设 —— 隐式导入路径,排查导入错乱先看它"
|
|
70
|
+
|
|
71
|
+
echo ""
|
|
72
|
+
echo "==== 结论 ===="
|
|
73
|
+
if [ -n "$Y" ]; then echo "待处理:$Y"; else echo "环境基本健康。"; fi
|
|
74
|
+
echo "处置对照: dev-python 版本与环境节;新机配置走 dev-toolchain。"
|
|
75
|
+
exit 0
|