@1aboveio/skills 0.0.0-stage → 1.0.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 +30 -2
- package/bin/cli.mjs +14 -0
- package/bin/select-core.mjs +172 -0
- package/package.json +146 -4
- package/skills/app-dev/airflow/LICENSE +3 -0
- package/skills/app-dev/airflow/SKILL.md +199 -0
- package/skills/app-dev/airflow/release-check.mjs +93 -0
- package/skills/app-dev/android-foundation/LICENSE +3 -0
- package/skills/app-dev/android-foundation/SKILL.md +192 -0
- package/skills/app-dev/android-foundation/assets/android-ci-job.yml +217 -0
- package/skills/app-dev/android-foundation/references/ci.md +87 -0
- package/skills/app-dev/android-foundation/references/gotchas.md +221 -0
- package/skills/app-dev/android-foundation/references/setup.md +164 -0
- package/skills/app-dev/android-foundation/release-check.mjs +93 -0
- package/skills/app-dev/android-foundation/scripts/device-run.sh +176 -0
- package/skills/app-dev/android-foundation/scripts/device-run.test.mjs +172 -0
- package/skills/app-dev/app-debug/LICENSE +3 -0
- package/skills/app-dev/app-debug/SKILL.md +110 -0
- package/skills/app-dev/app-debug/references/common-errors.md +128 -0
- package/skills/app-dev/app-debug/release-check.mjs +93 -0
- package/skills/app-dev/better-auth/LICENSE +3 -0
- package/skills/app-dev/better-auth/SKILL.md +598 -0
- package/skills/app-dev/better-auth/references/feishu-api.md +270 -0
- package/skills/app-dev/better-auth/release-check.mjs +93 -0
- package/skills/app-dev/data-catalog/LICENSE +3 -0
- package/skills/app-dev/data-catalog/SKILL.md +204 -0
- package/skills/app-dev/data-catalog/agents/openai.yaml +3 -0
- package/skills/app-dev/data-catalog/references/data-catalog-conventions.md +75 -0
- package/skills/app-dev/data-catalog/references/field-definitions.md +116 -0
- package/skills/app-dev/data-catalog/references/format.md +121 -0
- package/skills/app-dev/data-catalog/release-check.mjs +93 -0
- package/skills/app-dev/data-catalog/scripts/data-catalog.test.mjs +36 -0
- package/skills/app-dev/data-catalog/scripts/data_catalog.py +1392 -0
- package/skills/app-dev/data-catalog/scripts/persist-conventions-core.mjs +117 -0
- package/skills/app-dev/data-catalog/scripts/persist-conventions.mjs +17 -0
- package/skills/app-dev/data-catalog/scripts/test_data_catalog.py +571 -0
- package/skills/app-dev/ios-foundation/LICENSE +3 -0
- package/skills/app-dev/ios-foundation/SKILL.md +184 -0
- package/skills/app-dev/ios-foundation/references/setup.md +243 -0
- package/skills/app-dev/ios-foundation/release-check.mjs +93 -0
- package/skills/app-dev/monorepo/LICENSE +3 -0
- package/skills/app-dev/monorepo/SKILL.md +462 -0
- package/skills/app-dev/monorepo/release-check.mjs +93 -0
- package/skills/app-dev/nextjs-fullstack/LICENSE +3 -0
- package/skills/app-dev/nextjs-fullstack/SKILL.md +211 -0
- package/skills/app-dev/nextjs-fullstack/conventions.md +318 -0
- package/skills/app-dev/nextjs-fullstack/frontend-conventions.md +61 -0
- package/skills/app-dev/nextjs-fullstack/nextjs16.md +287 -0
- package/skills/app-dev/nextjs-fullstack/release-check.mjs +93 -0
- package/skills/app-dev/nextjs-fullstack/server-actions.md +409 -0
- package/skills/app-dev/prisma-setup/LICENSE +3 -0
- package/skills/app-dev/prisma-setup/SKILL.md +181 -0
- package/skills/app-dev/prisma-setup/nextjs.md +258 -0
- package/skills/app-dev/prisma-setup/release-check.mjs +93 -0
- package/skills/app-dev/prisma-setup/turborepo.md +301 -0
- package/skills/app-dev/pyspark/LICENSE +3 -0
- package/skills/app-dev/pyspark/SKILL.md +127 -0
- package/skills/app-dev/pyspark/assets/templates/etl.py +748 -0
- package/skills/app-dev/pyspark/assets/templates/utils/__init__.py +1 -0
- package/skills/app-dev/pyspark/assets/templates/utils/hudi_metadata.py +14 -0
- package/skills/app-dev/pyspark/references/diagnosis-and-profiling.md +169 -0
- package/skills/app-dev/pyspark/references/etl-contract.md +129 -0
- package/skills/app-dev/pyspark/references/production-validation.md +131 -0
- package/skills/app-dev/pyspark/references/reconciliation.md +38 -0
- package/skills/app-dev/pyspark/references/transformation-design.md +190 -0
- package/skills/app-dev/pyspark/references/velocity-feature-calculation.md +193 -0
- package/skills/app-dev/pyspark/release-check.mjs +93 -0
- package/skills/app-dev/pyspark/scripts/spark_eventlog_summary.py +223 -0
- package/skills/app-dev/python-backend/LICENSE +3 -0
- package/skills/app-dev/python-backend/SKILL.md +325 -0
- package/skills/app-dev/python-backend/assets/uv-install.sh +48 -0
- package/skills/app-dev/python-backend/references/uv-installs.md +83 -0
- package/skills/app-dev/python-backend/release-check.mjs +93 -0
- package/skills/app-dev/shadcn/LICENSE +3 -0
- package/skills/app-dev/shadcn/SKILL.md +120 -0
- package/skills/app-dev/shadcn/assets/shadcn-small.png +0 -0
- package/skills/app-dev/shadcn/assets/shadcn.png +0 -0
- package/skills/app-dev/shadcn/cli.md +411 -0
- package/skills/app-dev/shadcn/customization.md +224 -0
- package/skills/app-dev/shadcn/mcp.md +101 -0
- package/skills/app-dev/shadcn/release-check.mjs +93 -0
- package/skills/app-dev/shadcn/rules/base-vs-radix.md +323 -0
- package/skills/app-dev/shadcn/rules/component-selection.md +67 -0
- package/skills/app-dev/shadcn/rules/composition.md +195 -0
- package/skills/app-dev/shadcn/rules/data-table.md +201 -0
- package/skills/app-dev/shadcn/rules/forms.md +255 -0
- package/skills/app-dev/shadcn/rules/icons.md +103 -0
- package/skills/app-dev/shadcn/rules/styling.md +167 -0
- package/skills/app-dev/zod-v4/LICENSE +3 -0
- package/skills/app-dev/zod-v4/SKILL.md +286 -0
- package/skills/app-dev/zod-v4/release-check.mjs +93 -0
- package/skills/cicd/cloud-build/LICENSE +3 -0
- package/skills/cicd/cloud-build/SKILL.md +707 -0
- package/skills/cicd/cloud-build/release-check.mjs +93 -0
- package/skills/cicd/cloud-debug/LICENSE +3 -0
- package/skills/cicd/cloud-debug/SKILL.md +315 -0
- package/skills/cicd/cloud-debug/references/build-failures.md +238 -0
- package/skills/cicd/cloud-debug/references/deploy-failures.md +376 -0
- package/skills/cicd/cloud-debug/references/pipeline-failures.md +378 -0
- package/skills/cicd/cloud-debug/release-check.mjs +93 -0
- package/skills/cicd/cloud-deploy/LICENSE +3 -0
- package/skills/cicd/cloud-deploy/SKILL.md +230 -0
- package/skills/cicd/cloud-deploy/references/config-templates.md +257 -0
- package/skills/cicd/cloud-deploy/release-check.mjs +93 -0
- package/skills/cicd/docker/LICENSE +3 -0
- package/skills/cicd/docker/SKILL.md +151 -0
- package/skills/cicd/docker/release-check.mjs +93 -0
- package/skills/cicd/github-actions/LICENSE +3 -0
- package/skills/cicd/github-actions/SKILL.md +111 -0
- package/skills/cicd/github-actions/references/audit-profile-optimize.md +150 -0
- package/skills/cicd/github-actions/references/ci-case-studies.md +141 -0
- package/skills/cicd/github-actions/references/conditional-ci.md +214 -0
- package/skills/cicd/github-actions/references/debugging.md +13 -0
- package/skills/cicd/github-actions/references/pipeline.md +87 -0
- package/skills/cicd/github-actions/references/post-deploy-and-publishing.md +33 -0
- package/skills/cicd/github-actions/references/runners.md +253 -0
- package/skills/cicd/github-actions/references/security.md +29 -0
- package/skills/cicd/github-actions/references/speed-and-audit.md +115 -0
- package/skills/cicd/github-actions/references/two-pass-reading.md +92 -0
- package/skills/cicd/github-actions/release-check.mjs +93 -0
- package/skills/cicd/github-actions/scripts/ci-run-audit-core.mjs +612 -0
- package/skills/cicd/github-actions/scripts/ci-run-audit.mjs +4 -0
- package/skills/cicd/github-actions/scripts/ci-run-audit.test.mjs +637 -0
- package/skills/cicd/github-flow/LICENSE +3 -0
- package/skills/cicd/github-flow/SKILL.md +123 -0
- package/skills/cicd/github-flow/references/ci-conventions.md +14 -0
- package/skills/cicd/github-flow/release-check.mjs +93 -0
- package/skills/cicd/github-flow/scripts/flow-core.mjs +105 -0
- package/skills/cicd/github-flow/scripts/flow.mjs +81 -0
- package/skills/cicd/github-flow/scripts/flow.test.mjs +114 -0
- package/skills/cicd/github-flow/scripts/persist-conventions-core.mjs +117 -0
- package/skills/cicd/github-flow/scripts/persist-conventions.mjs +49 -0
- package/skills/cicd/github-flow/scripts/persist-conventions.test.mjs +108 -0
- package/skills/cicd/google-cloud/LICENSE +3 -0
- package/skills/cicd/google-cloud/SKILL.md +119 -0
- package/skills/cicd/google-cloud/references/gcs.md +469 -0
- package/skills/cicd/google-cloud/references/iam.md +451 -0
- package/skills/cicd/google-cloud/references/project.md +349 -0
- package/skills/cicd/google-cloud/references/secrets.md +336 -0
- package/skills/cicd/google-cloud/references/vpc.md +312 -0
- package/skills/cicd/google-cloud/release-check.mjs +93 -0
- package/skills/cicd/google-cloud/scripts/create-sa.sh +36 -0
- package/skills/cicd/google-cloud/scripts/gcp-config.sh +31 -0
- package/skills/cicd/google-cloud/scripts/grant-iap.sh +41 -0
- package/skills/cicd/google-cloud/scripts/setup-secrets.sh +48 -0
- package/skills/cicd/mergify/LICENSE +3 -0
- package/skills/cicd/mergify/SKILL.md +102 -0
- package/skills/cicd/mergify/assets/templates/mergify.yml +215 -0
- package/skills/cicd/mergify/assets/templates/ruleset.json +46 -0
- package/skills/cicd/mergify/references/branch-protection.md +282 -0
- package/skills/cicd/mergify/references/configuration.md +274 -0
- package/skills/cicd/mergify/references/diagnosis.md +109 -0
- package/skills/cicd/mergify/references/stacks.md +84 -0
- package/skills/cicd/mergify/references/traps.md +119 -0
- package/skills/cicd/mergify/references/watch-contract.md +274 -0
- package/skills/cicd/mergify/release-check.mjs +93 -0
- package/skills/cicd/mergify/scripts/audit-core.mjs +208 -0
- package/skills/cicd/mergify/scripts/audit.mjs +4 -0
- package/skills/cicd/mergify/scripts/audit.test.mjs +201 -0
- package/skills/cicd/mergify/scripts/entrypoints.test.mjs +106 -0
- package/skills/cicd/mergify/scripts/pr-620-mergify-comments.fixture.json +30 -0
- package/skills/cicd/mergify/scripts/stack-push-core.mjs +258 -0
- package/skills/cicd/mergify/scripts/stack-push.mjs +4 -0
- package/skills/cicd/mergify/scripts/stack-push.test.mjs +233 -0
- package/skills/cicd/mergify/scripts/watch-pr-delivery-core.mjs +1065 -0
- package/skills/cicd/mergify/scripts/watch-pr-delivery.mjs +4 -0
- package/skills/cicd/mergify/scripts/watch-pr-delivery.test.mjs +1826 -0
- package/skills/cicd/podman/LICENSE +3 -0
- package/skills/cicd/podman/SKILL.md +71 -0
- package/skills/cicd/podman/agents/openai.yaml +4 -0
- package/skills/cicd/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
- package/skills/cicd/podman/assets/templates/podman-service-override.conf +3 -0
- package/skills/cicd/podman/references/compose-compatibility.md +70 -0
- package/skills/cicd/podman/references/networking-and-ports.md +74 -0
- package/skills/cicd/podman/references/rootless-services-and-sockets.md +156 -0
- package/skills/cicd/podman/references/troubleshooting.md +98 -0
- package/skills/cicd/podman/release-check.mjs +93 -0
- package/skills/content/article-review/LICENSE +3 -0
- package/skills/content/article-review/SKILL.md +66 -0
- package/skills/content/article-review/references/report-format.md +68 -0
- package/skills/content/article-review/references/template-guide.md +79 -0
- package/skills/content/article-review/references/template-wechat-payments.md +125 -0
- package/skills/content/article-review/release-check.mjs +93 -0
- package/skills/content/article-to-image/LICENSE +3 -0
- package/skills/content/article-to-image/SKILL.md +91 -0
- package/skills/content/article-to-image/references/formats.md +53 -0
- package/skills/content/article-to-image/release-check.mjs +93 -0
- package/skills/content/flowchart-svg/LICENSE +3 -0
- package/skills/content/flowchart-svg/SKILL.md +43 -0
- package/skills/content/flowchart-svg/release-check.mjs +93 -0
- package/skills/content/flowchart-svg/scripts/export_png.sh +8 -0
- package/skills/content/image-gen/LICENSE +3 -0
- package/skills/content/image-gen/SKILL.md +192 -0
- package/skills/content/image-gen/release-check.mjs +93 -0
- package/skills/content/image-gen/scripts/credentials.mjs +217 -0
- package/skills/content/image-gen/scripts/credentials.test.mjs +212 -0
- package/skills/content/image-gen/scripts/generate.mjs +240 -0
- package/skills/content/image-gen/scripts/options.mjs +293 -0
- package/skills/content/image-gen/scripts/options.test.mjs +245 -0
- package/skills/content/mermaid/LICENSE +3 -0
- package/skills/content/mermaid/SKILL.md +635 -0
- package/skills/content/mermaid/release-check.mjs +93 -0
- package/skills/content/wechat-article-writer/LICENSE +3 -0
- package/skills/content/wechat-article-writer/SKILL.md +92 -0
- package/skills/content/wechat-article-writer/references/style-selector.md +133 -0
- package/skills/content/wechat-article-writer/references/writing-rules.md +152 -0
- package/skills/content/wechat-article-writer/release-check.mjs +93 -0
- package/skills/content/wechat-article-writer/templates/wechat-comparison.md +52 -0
- package/skills/content/wechat-article-writer/templates/wechat-howto.md +51 -0
- package/skills/content/wechat-article-writer/templates/wechat-insight.md +50 -0
- package/skills/content/wechat-article-writer/templates/wechat-pitfall.md +52 -0
- package/skills/content/wechat-publisher/LICENSE +3 -0
- package/skills/content/wechat-publisher/SKILL.md +171 -0
- package/skills/content/wechat-publisher/references/api.md +105 -0
- package/skills/content/wechat-publisher/references/layout-rules.md +57 -0
- package/skills/content/wechat-publisher/references/wechat-safe-template.html +86 -0
- package/skills/content/wechat-publisher/release-check.mjs +93 -0
- package/skills/content/wechat-publisher/scripts/md_to_wechat_html.py +194 -0
- package/skills/content/wechat-publisher/scripts/publish.py +239 -0
- package/skills/content/wechat-search/LICENSE +3 -0
- package/skills/content/wechat-search/SKILL.md +211 -0
- package/skills/content/wechat-search/release-check.mjs +93 -0
- package/skills/content/wechat-search/scripts/start-chrome.sh +83 -0
- package/skills/content/xai-search/LICENSE +3 -0
- package/skills/content/xai-search/SKILL.md +79 -0
- package/skills/content/xai-search/release-check.mjs +93 -0
- package/skills/content/xai-search/scripts/xai_search.sh +187 -0
- package/skills/content/xai-search/tests/smoke_test.sh +36 -0
- package/skills/core/distill-writing/LICENSE +3 -0
- package/skills/core/distill-writing/SKILL.md +74 -0
- package/skills/core/distill-writing/references/extraction.md +95 -0
- package/skills/core/distill-writing/references/updating.md +46 -0
- package/skills/core/distill-writing/release-check.mjs +93 -0
- package/skills/core/doc-to-md/LICENSE +3 -0
- package/skills/core/doc-to-md/SKILL.md +78 -0
- package/skills/core/doc-to-md/release-check.mjs +93 -0
- package/skills/core/doc-to-md/scripts/convert.py +157 -0
- package/skills/core/editorial-review/LICENSE +3 -0
- package/skills/core/editorial-review/SKILL.md +79 -0
- package/skills/core/editorial-review/references/checklist.md +94 -0
- package/skills/core/editorial-review/release-check.mjs +93 -0
- package/skills/core/house-style/LICENSE +3 -0
- package/skills/core/house-style/SKILL.md +33 -0
- package/skills/core/house-style/references/defaults.md +66 -0
- package/skills/core/house-style/references/rules.md +267 -0
- package/skills/core/house-style/references/sources.md +27 -0
- package/skills/core/house-style/references/style-en.md +131 -0
- package/skills/core/house-style/references/style-zh.md +141 -0
- package/skills/core/house-style/references/terminology-zh.md +223 -0
- package/skills/core/house-style/release-check.mjs +93 -0
- package/skills/core/house-style/templates/brd.md +103 -0
- package/skills/core/house-style/templates/commercial-proposal.md +93 -0
- package/skills/core/house-style/templates/compliance-policy.md +109 -0
- package/skills/core/house-style/templates/gap-analysis.md +105 -0
- package/skills/core/house-style/templates/general.md +63 -0
- package/skills/core/house-style/templates/integration-guide.md +98 -0
- package/skills/core/house-style/templates/prd.md +81 -0
- package/skills/core/house-style/templates/risk-operations-procedure.md +94 -0
- package/skills/core/house-style/templates/technical-spec.md +96 -0
- package/skills/core/polish-cn/LICENSE +3 -0
- package/skills/core/polish-cn/SKILL.md +102 -0
- package/skills/core/polish-cn/references/brief.md +93 -0
- package/skills/core/polish-cn/references/models.md +76 -0
- package/skills/core/polish-cn/release-check.mjs +93 -0
- package/skills/core/polish-cn/scripts/polish-cn.test.mjs +244 -0
- package/skills/core/polish-cn/scripts/polish_blocks.py +489 -0
- package/skills/core/reg-parser/LICENSE +3 -0
- package/skills/core/reg-parser/SKILL.md +212 -0
- package/skills/core/reg-parser/references/checklist-schema.md +223 -0
- package/skills/core/reg-parser/references/checklists/hk-amlo-checklist.json +1306 -0
- package/skills/core/reg-parser/references/checklists/hk-amlo-checklist.md +469 -0
- package/skills/core/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.json +634 -0
- package/skills/core/reg-parser/references/checklists/hk-fi-corporate-onboarding-cdd-checklist.md +233 -0
- package/skills/core/reg-parser/references/checklists/hk-mso-guideline-checklist.json +2194 -0
- package/skills/core/reg-parser/references/checklists/hk-mso-guideline-checklist.md +771 -0
- package/skills/core/reg-parser/references/checklists/kyc-aml-checklist.md +258 -0
- package/skills/core/reg-parser/references/checklists/visa-vars-checklist.md +1058 -0
- package/skills/core/reg-parser/references/mandates/hk-amlo-cap615.md +389 -0
- package/skills/core/reg-parser/references/mandates/visa-vars.md +205 -0
- package/skills/core/reg-parser/release-check.mjs +93 -0
- package/skills/core/reg-parser/scripts/compare_checklist.py +230 -0
- package/skills/core/reg-parser/scripts/dump_checklist.py +361 -0
- package/skills/core/reg-parser/scripts/preprocess-mandate.sh +187 -0
- package/skills/core/reg-parser/scripts/reg-parser.test.mjs +165 -0
- package/skills/core/reg-parser/scripts/test_quarantine.sh +105 -0
- package/skills/core/reg-parser/scripts/validate_checklist.py +563 -0
- package/skills/core/reg-parser/scripts/validate_mandate.py +273 -0
- package/skills/core/terminology/LICENSE +3 -0
- package/skills/core/terminology/SKILL.md +62 -0
- package/skills/core/terminology/references/format.md +50 -0
- package/skills/core/terminology/references/init.md +32 -0
- package/skills/core/terminology/release-check.mjs +93 -0
- package/skills/core/write-doc/LICENSE +3 -0
- package/skills/core/write-doc/SKILL.md +141 -0
- package/skills/core/write-doc/references/bilingual.md +60 -0
- package/skills/core/write-doc/release-check.mjs +93 -0
- package/skills/engineering/better-review/LICENSE +3 -0
- package/skills/engineering/better-review/SKILL.md +249 -0
- package/skills/engineering/better-review/agents/openai.yaml +9 -0
- package/skills/engineering/better-review/references/domain-hazards.md +53 -0
- package/skills/engineering/better-review/references/passes.md +147 -0
- package/skills/engineering/better-review/references/result.md +151 -0
- package/skills/engineering/better-review/release-check.mjs +93 -0
- package/skills/engineering/better-review/scripts/pr-context.mjs +212 -0
- package/skills/engineering/better-review/scripts/pr-context.test.mjs +168 -0
- package/skills/engineering/better-review/scripts/rereview-scope.mjs +503 -0
- package/skills/engineering/better-review/scripts/rereview-scope.test.mjs +587 -0
- package/skills/engineering/better-review/scripts/scan-diff.mjs +365 -0
- package/skills/engineering/better-review/scripts/scan-diff.test.mjs +414 -0
- package/skills/engineering/better-review/scripts/vendor-sync.test.mjs +96 -0
- package/skills/engineering/e2e-test/LICENSE +3 -0
- package/skills/engineering/e2e-test/SKILL.md +98 -0
- package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +24 -0
- package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +73 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +144 -0
- package/skills/engineering/e2e-test/references/ci-integration.md +25 -0
- package/skills/engineering/e2e-test/references/ci-playwright-container.md +290 -0
- package/skills/engineering/e2e-test/references/presentation-sweep.md +104 -0
- package/skills/engineering/e2e-test/references/reviewing.md +41 -0
- package/skills/engineering/e2e-test/references/route-manifest.md +51 -0
- package/skills/engineering/e2e-test/release-check.mjs +93 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.test.mjs +106 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.test.mjs +117 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.test.mjs +69 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.test.mjs +98 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +147 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.test.mjs +71 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.test.mjs +59 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +82 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.test.mjs +76 -0
- package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
- package/skills/engineering/engineering-runtime/LICENSE +3 -0
- package/skills/engineering/engineering-runtime/SKILL.md +11 -0
- package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/engineering-runtime/coherence/workflow.json +597 -0
- package/skills/engineering/engineering-runtime/engineering-runtime.test.mjs +68 -0
- package/skills/engineering/engineering-runtime/release-check.mjs +93 -0
- package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
- package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.mjs +187 -0
- package/skills/engineering/engineering-runtime/scripts/invocation-policy.test.mjs +95 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.mjs +79 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.test.mjs +288 -0
- package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
- package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
- package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.test.mjs +96 -0
- package/skills/engineering/engineering-runtime/scripts/review-completion.mjs +56 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +595 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +189 -0
- package/skills/engineering/engineering-runtime/scripts/yaml-mapping.mjs +18 -0
- package/skills/engineering/ensure-coverage/LICENSE +3 -0
- package/skills/engineering/ensure-coverage/SKILL.md +129 -0
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +92 -0
- package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +85 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
- package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +19 -0
- package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +57 -0
- package/skills/engineering/ensure-coverage/references/depth/test-smells.md +39 -0
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +44 -0
- package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +110 -0
- package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +35 -0
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +64 -0
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +27 -0
- package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +56 -0
- package/skills/engineering/ensure-coverage/release-check.mjs +93 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +67 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +140 -0
- package/skills/engineering/ensure-coverage/scripts/README.md +99 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +182 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.test.mjs +96 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +105 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.test.mjs +47 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +137 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.test.mjs +86 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +674 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.test.mjs +447 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.test.mjs +552 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +282 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.test.mjs +289 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.test.mjs +119 -0
- package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
- package/skills/engineering/golden-path/LICENSE +3 -0
- package/skills/engineering/golden-path/SKILL.md +230 -0
- package/skills/engineering/golden-path/agents/openai.yaml +3 -0
- package/skills/engineering/golden-path/assets/golden-paths.example.json +57 -0
- package/skills/engineering/golden-path/references/contract.md +239 -0
- package/skills/engineering/golden-path/references/migration.md +111 -0
- package/skills/engineering/golden-path/release-check.mjs +93 -0
- package/skills/engineering/golden-path/scripts/golden-path-core.mjs +1779 -0
- package/skills/engineering/golden-path/scripts/golden-path.mjs +6 -0
- package/skills/engineering/golden-path/scripts/golden-path.test.mjs +1457 -0
- package/skills/engineering/harness-runtime/LICENSE +3 -0
- package/skills/engineering/harness-runtime/SKILL.md +19 -0
- package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
- package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
- package/skills/engineering/harness-runtime/contracts.md +15 -0
- package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
- package/skills/engineering/harness-runtime/discover-models.test.mjs +363 -0
- package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
- package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
- package/skills/engineering/harness-runtime/harness-runtime.test.mjs +967 -0
- package/skills/engineering/harness-runtime/index.mjs +767 -0
- package/skills/engineering/harness-runtime/model-catalog-seed.test.mjs +829 -0
- package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
- package/skills/engineering/harness-runtime/model-catalog.test.mjs +366 -0
- package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
- package/skills/engineering/harness-runtime/references/model-catalog-seed.json +408 -0
- package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
- package/skills/engineering/harness-runtime/release-check.mjs +93 -0
- package/skills/engineering/resolve-issues/LICENSE +3 -0
- package/skills/engineering/resolve-issues/SKILL.md +250 -0
- package/skills/engineering/resolve-issues/agents/openai.yaml +9 -0
- package/skills/engineering/resolve-issues/plugin-hooks.json +17 -0
- package/skills/engineering/resolve-issues/references/canary.md +28 -0
- package/skills/engineering/resolve-issues/references/ci.md +105 -0
- package/skills/engineering/resolve-issues/references/done.md +25 -0
- package/skills/engineering/resolve-issues/references/dropbox.md +90 -0
- package/skills/engineering/resolve-issues/references/expire.md +318 -0
- package/skills/engineering/resolve-issues/references/exploration.md +202 -0
- package/skills/engineering/resolve-issues/references/implementation.md +303 -0
- package/skills/engineering/resolve-issues/references/preflight.md +445 -0
- package/skills/engineering/resolve-issues/references/review.md +228 -0
- package/skills/engineering/resolve-issues/references/shared-modules.md +44 -0
- package/skills/engineering/resolve-issues/references/task-plan.md +264 -0
- package/skills/engineering/resolve-issues/release-check.mjs +93 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +364 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.test.mjs +280 -0
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/dropbox.mjs +473 -0
- package/skills/engineering/resolve-issues/scripts/dropbox.test.mjs +346 -0
- package/skills/engineering/resolve-issues/scripts/findings-reuse.mjs +98 -0
- package/skills/engineering/resolve-issues/scripts/findings-reuse.test.mjs +88 -0
- package/skills/engineering/resolve-issues/scripts/github-reviews.mjs +384 -0
- package/skills/engineering/resolve-issues/scripts/github-reviews.test.mjs +264 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.mjs +135 -0
- package/skills/engineering/resolve-issues/scripts/install-hooks.test.mjs +79 -0
- package/skills/engineering/resolve-issues/scripts/issue-tree.mjs +162 -0
- package/skills/engineering/resolve-issues/scripts/issue-tree.test.mjs +107 -0
- package/skills/engineering/resolve-issues/scripts/manual-invocation.test.mjs +14 -0
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/next-actions-capacity.test.mjs +149 -0
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +856 -0
- package/skills/engineering/resolve-issues/scripts/next-actions.test.mjs +915 -0
- package/skills/engineering/resolve-issues/scripts/plan-sync.mjs +269 -0
- package/skills/engineering/resolve-issues/scripts/plan-sync.test.mjs +156 -0
- package/skills/engineering/resolve-issues/scripts/preflight-models.mjs +736 -0
- package/skills/engineering/resolve-issues/scripts/preflight-models.test.mjs +448 -0
- package/skills/engineering/resolve-issues/scripts/ready-check.mjs +185 -0
- package/skills/engineering/resolve-issues/scripts/ready-check.test.mjs +217 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +98 -0
- package/skills/engineering/resolve-issues/scripts/rehydrate.test.mjs +91 -0
- package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +509 -0
- package/skills/engineering/resolve-issues/scripts/review-verdict.test.mjs +1060 -0
- package/skills/engineering/resolve-issues/scripts/size-check.mjs +492 -0
- package/skills/engineering/resolve-issues/scripts/size-check.test.mjs +458 -0
- package/skills/engineering/resolve-release/LICENSE +3 -0
- package/skills/engineering/resolve-release/SKILL.md +215 -0
- package/skills/engineering/resolve-release/agents/openai.yaml +8 -0
- package/skills/engineering/resolve-release/flows/cloud-run-canary.md +13 -0
- package/skills/engineering/resolve-release/flows/cloud-run.md +7 -0
- package/skills/engineering/resolve-release/flows/root-tag-npm.md +13 -0
- package/skills/engineering/resolve-release/flows/workspace-npm.md +22 -0
- package/skills/engineering/resolve-release/references/canary.md +51 -0
- package/skills/engineering/resolve-release/references/candidate.md +41 -0
- package/skills/engineering/resolve-release/references/cut.md +131 -0
- package/skills/engineering/resolve-release/references/dark-launch.md +66 -0
- package/skills/engineering/resolve-release/references/flows.md +150 -0
- package/skills/engineering/resolve-release/references/preflight.md +154 -0
- package/skills/engineering/resolve-release/references/prepared-metadata.md +260 -0
- package/skills/engineering/resolve-release/references/promotion.md +82 -0
- package/skills/engineering/resolve-release/references/publish.md +232 -0
- package/skills/engineering/resolve-release/references/workspace-npm.md +103 -0
- package/skills/engineering/resolve-release/release-check.mjs +93 -0
- package/skills/engineering/resolve-release/scripts/apply.mjs +212 -0
- package/skills/engineering/resolve-release/scripts/apply.test.mjs +99 -0
- package/skills/engineering/resolve-release/scripts/dark-flags.mjs +134 -0
- package/skills/engineering/resolve-release/scripts/dark-flags.test.mjs +100 -0
- package/skills/engineering/resolve-release/scripts/flow.mjs +500 -0
- package/skills/engineering/resolve-release/scripts/flow.test.mjs +340 -0
- package/skills/engineering/resolve-release/scripts/green-head.mjs +231 -0
- package/skills/engineering/resolve-release/scripts/green-head.test.mjs +101 -0
- package/skills/engineering/resolve-release/scripts/npm-version-absence.mjs +138 -0
- package/skills/engineering/resolve-release/scripts/npm-version-absence.test.mjs +426 -0
- package/skills/engineering/resolve-release/scripts/plan-npm.test.mjs +659 -0
- package/skills/engineering/resolve-release/scripts/plan-toml-boundary.test.mjs +317 -0
- package/skills/engineering/resolve-release/scripts/plan-uv.test.mjs +291 -0
- package/skills/engineering/resolve-release/scripts/plan.mjs +806 -0
- package/skills/engineering/resolve-release/scripts/plan.test.mjs +428 -0
- package/skills/engineering/rush-issues/LICENSE +3 -0
- package/skills/engineering/rush-issues/SKILL.md +58 -0
- package/skills/engineering/rush-issues/agents/openai.yaml +8 -0
- package/skills/engineering/rush-issues/rehydrate.mjs +10 -0
- package/skills/engineering/rush-issues/release-check.mjs +93 -0
- package/skills/engineering/rush-release/LICENSE +3 -0
- package/skills/engineering/rush-release/SKILL.md +35 -0
- package/skills/engineering/rush-release/agents/openai.yaml +8 -0
- package/skills/engineering/rush-release/release-check.mjs +93 -0
- package/skills/engineering/test-quality/LICENSE +3 -0
- package/skills/engineering/test-quality/SKILL.md +79 -0
- package/skills/engineering/test-quality/references/audit.md +80 -0
- package/skills/engineering/test-quality/references/lint.md +24 -0
- package/skills/engineering/test-quality/references/principles.md +143 -0
- package/skills/engineering/test-quality/references/testing-conventions.md +9 -0
- package/skills/engineering/test-quality/release-check.mjs +93 -0
- package/skills/engineering/test-quality/scripts/lint-tests.mjs +574 -0
- package/skills/engineering/test-quality/scripts/lint-tests.test.mjs +591 -0
- package/skills/engineering/test-quality/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/test-quality/scripts/mock-policy-config.test.mjs +119 -0
- package/skills/engineering/test-quality/scripts/persist-conventions-core.mjs +117 -0
- package/skills/engineering/test-quality/scripts/persist-conventions.mjs +17 -0
- package/skills/engineering/test-quality/scripts/persist-conventions.test.mjs +104 -0
- package/skills/risk-compliance/compliance-audit/LICENSE +3 -0
- package/skills/risk-compliance/compliance-audit/SKILL.md +439 -0
- package/skills/risk-compliance/compliance-audit/references/findings-schema.md +293 -0
- package/skills/risk-compliance/compliance-audit/references/normalization-rules.md +45 -0
- package/skills/risk-compliance/compliance-audit/references/vars-checklist.md +1068 -0
- package/skills/risk-compliance/compliance-audit/references/vars-findings-schema.md +398 -0
- package/skills/risk-compliance/compliance-audit/release-check.mjs +93 -0
- package/skills/risk-compliance/compliance-audit/scripts/compliance-audit.test.mjs +14 -0
- package/skills/risk-compliance/compliance-audit/scripts/export_tracker_xlsx.py +221 -0
- package/skills/risk-compliance/compliance-audit/scripts/reconcile_tracker.py +458 -0
- package/skills/risk-compliance/compliance-audit/scripts/test_export_tracker_xlsx.py +97 -0
- package/skills/risk-compliance/compliance-audit/scripts/test_validate_tracker.py +157 -0
- package/skills/risk-compliance/compliance-audit/scripts/validate_tracker.py +829 -0
- package/skills/risk-compliance/contract-compare/LICENSE +3 -0
- package/skills/risk-compliance/contract-compare/SKILL.md +199 -0
- package/skills/risk-compliance/contract-compare/references/comparison-dimensions.md +209 -0
- package/skills/risk-compliance/contract-compare/release-check.mjs +93 -0
- package/skills/risk-compliance/contract-review/LICENSE +3 -0
- package/skills/risk-compliance/contract-review/SKILL.md +240 -0
- package/skills/risk-compliance/contract-review/references/review-criteria.md +223 -0
- package/skills/risk-compliance/contract-review/release-check.mjs +93 -0
- package/skills/risk-compliance/doc-authenticity/LICENSE +3 -0
- package/skills/risk-compliance/doc-authenticity/SKILL.md +160 -0
- package/skills/risk-compliance/doc-authenticity/agents/openai.yaml +8 -0
- package/skills/risk-compliance/doc-authenticity/manual-invocation.test.mjs +12 -0
- package/skills/risk-compliance/doc-authenticity/references/agreement.md +66 -0
- package/skills/risk-compliance/doc-authenticity/references/bank-statement.md +150 -0
- package/skills/risk-compliance/doc-authenticity/references/forensic-signals.md +157 -0
- package/skills/risk-compliance/doc-authenticity/references/image-signals.md +114 -0
- package/skills/risk-compliance/doc-authenticity/references/invoice.md +66 -0
- package/skills/risk-compliance/doc-authenticity/references/issuer-profiles.md +86 -0
- package/skills/risk-compliance/doc-authenticity/references/verdict-and-report.md +95 -0
- package/skills/risk-compliance/doc-authenticity/references/verdict.schema.json +81 -0
- package/skills/risk-compliance/doc-authenticity/release-check.mjs +93 -0
- package/skills/risk-compliance/doc-authenticity/scripts/image_forensics.py +294 -0
- package/skills/risk-compliance/doc-authenticity/scripts/pdf_forensics.py +401 -0
- package/skills/risk-compliance/doc-authenticity/scripts/validate_codes.py +224 -0
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.py +308 -0
- package/skills/risk-compliance/doc-authenticity/scripts/validate_verdict.test.mjs +212 -0
- package/skills/risk-compliance/fraud-analysis/LICENSE +3 -0
- package/skills/risk-compliance/fraud-analysis/SKILL.md +114 -0
- package/skills/risk-compliance/fraud-analysis/references/archetypes/authorized-payment-scam.md +41 -0
- package/skills/risk-compliance/fraud-analysis/references/archetypes/first-party-fraud.md +44 -0
- package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +27 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/bank-transfer.md +24 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +30 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +20 -0
- package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +20 -0
- package/skills/risk-compliance/fraud-analysis/references/feature-engineering.md +158 -0
- package/skills/risk-compliance/fraud-analysis/references/mechanisms/account-takeover.md +36 -0
- package/skills/risk-compliance/fraud-analysis/references/report-rationale.md +45 -0
- package/skills/risk-compliance/fraud-analysis/references/report-template.md +190 -0
- package/skills/risk-compliance/fraud-analysis/references/review-checklist.md +175 -0
- package/skills/risk-compliance/fraud-analysis/references/taxonomy.md +79 -0
- package/skills/risk-compliance/fraud-analysis/references/terminology.md +108 -0
- package/skills/risk-compliance/fraud-analysis/references/workflow.md +175 -0
- package/skills/risk-compliance/fraud-analysis/release-check.mjs +93 -0
- package/skills/risk-compliance/payment-analysis/LICENSE +3 -0
- package/skills/risk-compliance/payment-analysis/SKILL.md +180 -0
- package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +30 -0
- package/skills/risk-compliance/payment-analysis/references/chargebacks.md +208 -0
- package/skills/risk-compliance/payment-analysis/references/chinese-polish.md +51 -0
- package/skills/risk-compliance/payment-analysis/references/event-layers.md +127 -0
- package/skills/risk-compliance/payment-analysis/references/fx.md +59 -0
- package/skills/risk-compliance/payment-analysis/references/journey.md +79 -0
- package/skills/risk-compliance/payment-analysis/references/metrics.md +67 -0
- package/skills/risk-compliance/payment-analysis/references/report-template.md +119 -0
- package/skills/risk-compliance/payment-analysis/references/terminology.md +95 -0
- package/skills/risk-compliance/payment-analysis/references/visualization.md +56 -0
- package/skills/risk-compliance/payment-analysis/release-check.mjs +93 -0
- package/skills/risk-compliance/report-writing/LICENSE +3 -0
- package/skills/risk-compliance/report-writing/SKILL.md +220 -0
- package/skills/risk-compliance/report-writing/references/audit-report-template.md +121 -0
- package/skills/risk-compliance/report-writing/references/external-assessment-template.md +167 -0
- package/skills/risk-compliance/report-writing/references/management-report-template.md +145 -0
- package/skills/risk-compliance/report-writing/references/vars-report-template.md +224 -0
- package/skills/risk-compliance/report-writing/release-check.mjs +93 -0
- package/skills/risk-compliance/similar-domain/LICENSE +3 -0
- package/skills/risk-compliance/similar-domain/SKILL.md +203 -0
- package/skills/risk-compliance/similar-domain/references/entities.md +67 -0
- package/skills/risk-compliance/similar-domain/references/fingerprints.md +134 -0
- package/skills/risk-compliance/similar-domain/references/pivots.md +82 -0
- package/skills/risk-compliance/similar-domain/references/report-template.md +93 -0
- package/skills/risk-compliance/similar-domain/references/scoring.md +130 -0
- package/skills/risk-compliance/similar-domain/references/terminology.md +41 -0
- package/skills/risk-compliance/similar-domain/references/workflow.md +85 -0
- package/skills/risk-compliance/similar-domain/release-check.mjs +93 -0
- package/skills/risk-compliance/tld-detection/LICENSE +3 -0
- package/skills/risk-compliance/tld-detection/SKILL.md +245 -0
- package/skills/risk-compliance/tld-detection/agents/openai.yaml +9 -0
- package/skills/risk-compliance/tld-detection/references/chinese-polish.md +55 -0
- package/skills/risk-compliance/tld-detection/references/clean.md +51 -0
- package/skills/risk-compliance/tld-detection/references/clustering.md +235 -0
- package/skills/risk-compliance/tld-detection/references/decision.md +189 -0
- package/skills/risk-compliance/tld-detection/references/fx-conversion.md +232 -0
- package/skills/risk-compliance/tld-detection/references/report-template.md +272 -0
- package/skills/risk-compliance/tld-detection/references/streams.md +141 -0
- package/skills/risk-compliance/tld-detection/references/terminology.md +95 -0
- package/skills/risk-compliance/tld-detection/references/workflow.md +95 -0
- package/skills/risk-compliance/tld-detection/release-check.mjs +93 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +390 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.test.mjs +14 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +650 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.test.mjs +14 -0
- package/skills/risk-compliance/tld-detection/tests/test_detect_ladders.py +134 -0
- package/skills/risk-compliance/tld-detection/tests/test_detect_streams.py +520 -0
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
// Pick the review tier for a new HEAD, from the previous round's result file.
|
|
2
|
+
//
|
|
3
|
+
// node rereview-scope.mjs --prior <previous-result.json> --base <target-branch> [--head HEAD]
|
|
4
|
+
// [--write-skip <next-result.json>]
|
|
5
|
+
//
|
|
6
|
+
// Prints JSON with `tier`:
|
|
7
|
+
// skip no reviewer runs: the previous review passed and the PR's own changes are unchanged
|
|
8
|
+
// (the same HEAD; the same patch over a base that moved only outside the PR's files;
|
|
9
|
+
// or, with both reviewed commits at hand, every PR file's own changed lines the same,
|
|
10
|
+
// at the same places, after the base moved under them).
|
|
11
|
+
// With --write-skip, the script writes the record that carries the approval to
|
|
12
|
+
// this HEAD; CI on this HEAD is the proof.
|
|
13
|
+
// delta review `touchedFiles` (fix commits, and PR files the base moved under) in full
|
|
14
|
+
// depth and re-check `carriedFiles` only where they depend on what changed.
|
|
15
|
+
// full review the whole diff again; `reasons` names each trigger.
|
|
16
|
+
// The reviewer may widen the tier, never narrow it.
|
|
17
|
+
//
|
|
18
|
+
// A skip needs a previous review that is complete, anchored, and has no open P0/P1: a
|
|
19
|
+
// blocker is never carried, it is fixed. A delta is allowed only when the previous round covered the whole diff (every pass done
|
|
20
|
+
// or skipped for a stated reason, not oversize), and the fixes and integration changes
|
|
21
|
+
// since the last full round changed at most half the PR's lines in total. Conflicted
|
|
22
|
+
// files join the delta as `integrationFiles`; imported base lines do not count as fixes.
|
|
23
|
+
// Unbounded integration impact forces full. The base diff remains mandatory review input.
|
|
24
|
+
// Neither the round number nor a previous delta forces full: impact does. A rebase or
|
|
25
|
+
// metadata-only commit that leaves the PR's own patch unchanged reuses the review, even
|
|
26
|
+
// when the reviewed HEAD is gone, using a location-sensitive `patchFingerprint` as well
|
|
27
|
+
// as `patchId`. A reachable prior HEAD must also have no changed PR-file content before
|
|
28
|
+
// its source approval can carry. Anything this script cannot establish (unreachable
|
|
29
|
+
// history without both identities, or missing fields) forces full.
|
|
30
|
+
//
|
|
31
|
+
// The result file of each round records `patchId`, `patchFingerprint` and
|
|
32
|
+
// `fixLinesSinceFull` from this output (round 1 takes the identities from pr-context
|
|
33
|
+
// and `fixLinesSinceFull: 0`).
|
|
34
|
+
//
|
|
35
|
+
// On a delta it also hands the reviewer its setup, so the round starts reviewing at once:
|
|
36
|
+
// the open P0/P1 findings in full, the previous sweep points that sit in touched files, the
|
|
37
|
+
// names the fix diff defines or changes, every line in a carried file that uses one of them,
|
|
38
|
+
// and scan-diff's leads and findings for the fix diff alone.
|
|
39
|
+
//
|
|
40
|
+
// Exit codes: 0 tier printed, 2 usage error or unreadable prior result.
|
|
41
|
+
|
|
42
|
+
import { execFileSync } from 'node:child_process'
|
|
43
|
+
import { createHash } from 'node:crypto'
|
|
44
|
+
import fs from 'node:fs'
|
|
45
|
+
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
46
|
+
import { reviewCompletionProblems, reviewTier } from '../../engineering-runtime/scripts/review-completion.mjs'
|
|
47
|
+
import { scanDiff } from './scan-diff.mjs'
|
|
48
|
+
|
|
49
|
+
export const MAX_FIX_SHARE = 0.5
|
|
50
|
+
export const MAX_CALL_SITES = 200
|
|
51
|
+
export const MAX_FIX_DIFF_CHARS = 60000
|
|
52
|
+
|
|
53
|
+
const USAGE = 'usage: rereview-scope.mjs --prior <previous-result.json> --base <target-branch> [--head HEAD] [--write-skip <next-result.json>]'
|
|
54
|
+
export const TIERS = Object.freeze(['skip', 'delta', 'full'])
|
|
55
|
+
const isBlocking = (f) => f?.severity === 'P0' || f?.severity === 'P1'
|
|
56
|
+
|
|
57
|
+
export class RereviewScopeError extends Error {}
|
|
58
|
+
|
|
59
|
+
// ---- pure core ----
|
|
60
|
+
|
|
61
|
+
// Reasons the previous result cannot anchor a delta. Empty means it can.
|
|
62
|
+
export function priorProblems(prior) {
|
|
63
|
+
const problems = reviewCompletionProblems(prior, { requirePasses: true }).map((problem) => `previous ${problem}`)
|
|
64
|
+
if (typeof prior?.head !== 'string' || prior.head.trim() === '') problems.push('previous result has no head')
|
|
65
|
+
if (typeof prior?.mergeBase !== 'string' || prior.mergeBase.trim() === '') problems.push('previous result has no mergeBase')
|
|
66
|
+
if (!Number.isInteger(prior?.round) || prior.round < 1) problems.push('previous result has no round')
|
|
67
|
+
const tier = reviewTier(prior)
|
|
68
|
+
if (tier !== undefined && !TIERS.includes(tier)) problems.push(`previous round has unknown tier ${JSON.stringify(tier)}`)
|
|
69
|
+
if ((tier === 'delta' || tier === 'skip') && !(Number.isInteger(prior.fixLinesSinceFull) && prior.fixLinesSinceFull >= 0)) {
|
|
70
|
+
problems.push(`previous ${tier} round has no fixLinesSinceFull`)
|
|
71
|
+
}
|
|
72
|
+
if (prior?.oversize === true) problems.push('previous round was oversize')
|
|
73
|
+
if (Object.hasOwn(prior ?? {}, 'fixRound') && (!Number.isSafeInteger(prior.fixRound) || prior.fixRound < 1 || prior.fixRound > prior.round)) {
|
|
74
|
+
problems.push('previous fixRound must be a positive safe integer no greater than round')
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return problems
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Sum added + deleted lines from `git diff --numstat` output; binary files count as 1.
|
|
81
|
+
export function numstatLines(text) {
|
|
82
|
+
let total = 0
|
|
83
|
+
for (const line of (text || '').split('\n')) {
|
|
84
|
+
const m = line.match(/^(\d+|-)\t(\d+|-)\t/)
|
|
85
|
+
if (!m) continue
|
|
86
|
+
total += m[1] === '-' ? 1 : Number(m[1]) + Number(m[2])
|
|
87
|
+
}
|
|
88
|
+
return total
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// `samePatch`: the reviewed HEAD is gone, but the PR's own patch is identical to the one
|
|
92
|
+
// reviewed (a content-equivalent rebase), so nothing in the PR changed.
|
|
93
|
+
// `conflictFiles`: PR files the base moved under whose own PR changes also changed.
|
|
94
|
+
// `baseKnown`: the previous merge-base is in this repository, so base movement is known.
|
|
95
|
+
// `sameHead`: the HEAD is the one the previous round reviewed.
|
|
96
|
+
// `ownUnchanged`: every PR file's own changed lines are the ones reviewed, at the same places
|
|
97
|
+
// once the base's own edits are mapped out; only the base moved. CI on the new HEAD proves
|
|
98
|
+
// how the two fit together.
|
|
99
|
+
export function decideScope({ prior, round, prFiles, touchedFiles, baseMovedFiles, fixLines, prLines, priorHeadReachable, samePatch = false, sameHead = false, conflictFiles = [], integrationLines = 0, baseKnown = true, ownUnchanged = false }) {
|
|
100
|
+
const reasons = [...priorProblems(prior)]
|
|
101
|
+
if (!priorHeadReachable && !samePatch) reasons.push(`previous HEAD ${prior?.head} is not in this repository and its patch identities differ or are missing`)
|
|
102
|
+
if (!baseKnown) reasons.push(`previous merge-base ${prior?.mergeBase} is not in this repository`)
|
|
103
|
+
const prSet = new Set(prFiles)
|
|
104
|
+
const conflicts = new Set(conflictFiles)
|
|
105
|
+
const underPr = baseMovedFiles.filter((file) => prSet.has(file))
|
|
106
|
+
const conflicted = underPr.filter((file) => conflicts.has(file))
|
|
107
|
+
if (integrationLines === null) reasons.push('integration impact cannot be bounded; review the whole diff')
|
|
108
|
+
const mergeFiles = underPr.filter((file) => !conflicts.has(file))
|
|
109
|
+
const sinceFull = (reviewTier(prior) !== undefined && reviewTier(prior) !== 'full' && Number.isInteger(prior.fixLinesSinceFull) ? prior.fixLinesSinceFull : 0) + fixLines + (integrationLines ?? 0)
|
|
110
|
+
if (prLines > 0 && sinceFull / prLines > MAX_FIX_SHARE) {
|
|
111
|
+
reasons.push(`the fixes since the last full review changed ${sinceFull} of ${prLines} PR lines (more than ${MAX_FIX_SHARE * 100}%)`)
|
|
112
|
+
}
|
|
113
|
+
if (prLines === 0 && sinceFull > 0) reasons.push('the previously reviewed PR changes were removed')
|
|
114
|
+
const touched = new Set([...touchedFiles, ...mergeFiles, ...conflicted])
|
|
115
|
+
const passed = Array.isArray(prior?.findings) && !prior.findings.some(isBlocking)
|
|
116
|
+
const unchanged = sameHead || (samePatch && baseKnown && underPr.length === 0) || (ownUnchanged && baseKnown && priorHeadReachable)
|
|
117
|
+
const tier = reasons.length > 0 ? 'full' : passed && unchanged ? 'skip' : 'delta'
|
|
118
|
+
return {
|
|
119
|
+
tier,
|
|
120
|
+
reasons,
|
|
121
|
+
round,
|
|
122
|
+
touchedFiles: prFiles.filter((file) => touched.has(file)),
|
|
123
|
+
carriedFiles: prFiles.filter((file) => !touched.has(file)),
|
|
124
|
+
fixLines,
|
|
125
|
+
integrationLines,
|
|
126
|
+
prLines,
|
|
127
|
+
fixLinesSinceFull: tier === 'full' ? 0 : sinceFull,
|
|
128
|
+
mergeFiles,
|
|
129
|
+
integrationFiles: conflicted,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Names a diff defines or changes, from its added and removed lines (not context): top-level
|
|
134
|
+
// code definitions in JS/TS/Python-style syntax (unindented or exported; a local variable is
|
|
135
|
+
// nobody else's contract), plus Markdown headings as link anchors (`#slug`), since prose files
|
|
136
|
+
// link to each other by heading. Test files define nothing other code uses, so they are
|
|
137
|
+
// skipped. Best effort: a miss leaves the reviewer's own search as the only net, so this
|
|
138
|
+
// never replaces reading the fix diff.
|
|
139
|
+
const DEFINITION_PATTERNS = [
|
|
140
|
+
/^(?:export\s+(?:default\s+)?)?(?:async\s+)?(?:function\*?|class|def|interface|type|enum)\s+([A-Za-z_$][\w$]*)/,
|
|
141
|
+
/^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/,
|
|
142
|
+
/^\s*export\s+(?:default\s+)?(?:async\s+)?(?:function\*?|class|const|let|var|interface|type|enum)\s+([A-Za-z_$][\w$]*)/,
|
|
143
|
+
]
|
|
144
|
+
const TEST_FILE = /(^|\/)(__tests__|tests?)\/|[._-](test|spec)\.[cm]?[jt]sx?$|(^|\/)test_[^/]*\.py$|_test\.(py|go)$/
|
|
145
|
+
const NOT_NAMES = new Set(['if', 'for', 'while', 'switch', 'catch', 'function', 'return', 'constructor'])
|
|
146
|
+
|
|
147
|
+
export function headingSlug(text) {
|
|
148
|
+
return text.trim().toLowerCase().replace(/[`*_~]/g, '').replace(/[^\p{L}\p{N}\s-]/gu, '').replace(/\s/g, '-')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function changedSymbols(diffText) {
|
|
152
|
+
const names = new Set()
|
|
153
|
+
const anchors = new Set()
|
|
154
|
+
let file = ''
|
|
155
|
+
for (const raw of (diffText || '').split(/\r?\n/)) {
|
|
156
|
+
if (raw.startsWith('+++ ') || raw.startsWith('--- ')) { file = raw.slice(4).replace(/^[ab]\//, ''); continue }
|
|
157
|
+
if (!/^[+-]/.test(raw)) continue
|
|
158
|
+
const line = raw.slice(1)
|
|
159
|
+
if (/\.(md|mdx)$/i.test(file)) {
|
|
160
|
+
const h = line.match(/^#{1,6}\s+(.+?)\s*#*\s*$/)
|
|
161
|
+
if (h) anchors.add(`#${headingSlug(h[1])}`)
|
|
162
|
+
continue
|
|
163
|
+
}
|
|
164
|
+
if (TEST_FILE.test(file)) continue
|
|
165
|
+
for (const pattern of DEFINITION_PATTERNS) {
|
|
166
|
+
const m = line.match(pattern)
|
|
167
|
+
if (m && !NOT_NAMES.has(m[1]) && m[1].length > 2) names.add(m[1])
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { names: [...names].sort(), anchors: [...anchors].sort() }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// The previous round's sweep points whose location is a touched file.
|
|
174
|
+
export function sweepRecheck(prior, touchedFiles) {
|
|
175
|
+
const touched = new Set(touchedFiles)
|
|
176
|
+
const out = []
|
|
177
|
+
for (const sweep of prior?.sweeps ?? []) {
|
|
178
|
+
for (const point of sweep?.points ?? []) {
|
|
179
|
+
const file = String(point?.location ?? '').replace(/:\d+(?:-\d+)?$/, '')
|
|
180
|
+
if (touched.has(file)) out.push({ rule: sweep.rule, ...point })
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return out
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ---- git glue ----
|
|
187
|
+
|
|
188
|
+
function git(args) {
|
|
189
|
+
return execFileSync('git', args, { encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 }).trim()
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// The whitespace-preserving patch id of the PR's net diff, or null for an empty diff.
|
|
193
|
+
// Whitespace can change behavior (for example Python indentation), so it is not metadata.
|
|
194
|
+
export function prPatchId(mergeBase, head, paths = []) {
|
|
195
|
+
const diff = execFileSync('git', ['diff', '--binary', `${mergeBase}...${head}`, ...(paths.length ? ['--', ...paths] : [])], { encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 })
|
|
196
|
+
if (diff.trim() === '') return null
|
|
197
|
+
const out = execFileSync('git', ['patch-id', '--verbatim'], { input: diff, encoding: 'utf8' }).trim()
|
|
198
|
+
return out.split(/\s+/)[0] || null
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Unlike patch-id, this preserves hunk locations as well as whitespace and binary bytes.
|
|
202
|
+
// Ignore only blob ids: base edits outside the patch can change them after a rebase.
|
|
203
|
+
export function prPatchFingerprint(mergeBase, head) {
|
|
204
|
+
const diff = execFileSync('git', ['diff', '--binary', `${mergeBase}...${head}`], { encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 })
|
|
205
|
+
if (diff.trim() === '') return null
|
|
206
|
+
const patch = diff.split('\n').filter((line) => !/^index [0-9a-f]+\.\.[0-9a-f]+(?: \d+)?$/.test(line)).join('\n')
|
|
207
|
+
return createHash('sha256').update(patch).digest('hex')
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Compare the PR's own changed lines, not the old/new trees (which include base imports).
|
|
211
|
+
// Sequence comparison counts reordered changes too. Large or binary patches fail closed.
|
|
212
|
+
export function patchImpactLines(before, after, baseDiff = '') {
|
|
213
|
+
if (before === after) return 0
|
|
214
|
+
if (before.length + after.length > MAX_FIX_DIFF_CHARS * 2) return null
|
|
215
|
+
if (/^(?:Binary files |GIT binary patch)/m.test(before + '\n' + after)) return null
|
|
216
|
+
const baseHunks = [...baseDiff.matchAll(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/gm)]
|
|
217
|
+
.map((match) => ({ oldStart: Number(match[1]), oldCount: Number(match[2] ?? 1), newStart: Number(match[3]), newCount: Number(match[4] ?? 1) }))
|
|
218
|
+
// Map new-base anchors back to the reviewed base. Pure base insertions shift
|
|
219
|
+
// lines but not edit targets; anchors inside rewritten base hunks are new.
|
|
220
|
+
const reviewedAnchor = (line) => {
|
|
221
|
+
let offset = 0
|
|
222
|
+
for (const hunk of baseHunks) {
|
|
223
|
+
const start = hunk.newCount === 0 ? hunk.newStart + 1 : hunk.newStart
|
|
224
|
+
if (line < start) break
|
|
225
|
+
if (hunk.newCount > 0 && line < start + hunk.newCount) return `new:${line}`
|
|
226
|
+
offset += hunk.oldCount - hunk.newCount
|
|
227
|
+
}
|
|
228
|
+
return line + offset
|
|
229
|
+
}
|
|
230
|
+
const changed = (diff, mapAnchor = (line) => line) => {
|
|
231
|
+
const out = []
|
|
232
|
+
let hunk = false
|
|
233
|
+
let context = ''
|
|
234
|
+
let oldLine = 0
|
|
235
|
+
for (const line of diff.split('\n')) {
|
|
236
|
+
if (line.startsWith('diff --git ')) hunk = false
|
|
237
|
+
else if (line.startsWith('@@ ')) {
|
|
238
|
+
hunk = true
|
|
239
|
+
context = line.slice(line.indexOf(' @@') + 3)
|
|
240
|
+
oldLine = Number(/^@@ -(\d+)/.exec(line)?.[1])
|
|
241
|
+
} else if (hunk && /^[+-]/.test(line)) {
|
|
242
|
+
out.push(`${mapAnchor(oldLine)}\0${context}\0${line}`)
|
|
243
|
+
if (line.startsWith('-')) oldLine++
|
|
244
|
+
} else if (hunk && line.startsWith(' ')) oldLine++
|
|
245
|
+
}
|
|
246
|
+
return out
|
|
247
|
+
}
|
|
248
|
+
const a = changed(before)
|
|
249
|
+
const b = changed(after, reviewedAnchor)
|
|
250
|
+
if (a.length * b.length > 4_000_000) return null
|
|
251
|
+
let previous = new Uint32Array(b.length + 1)
|
|
252
|
+
for (const line of a) {
|
|
253
|
+
const current = new Uint32Array(b.length + 1)
|
|
254
|
+
for (let j = 1; j <= b.length; j++) {
|
|
255
|
+
current[j] = line === b[j - 1] ? previous[j - 1] + 1 : Math.max(previous[j], current[j - 1])
|
|
256
|
+
}
|
|
257
|
+
previous = current
|
|
258
|
+
}
|
|
259
|
+
const impact = a.length + b.length - 2 * previous[b.length]
|
|
260
|
+
return impact
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// True when a file's own PR lines are the reviewed ones at the same places, once the base's
|
|
264
|
+
// edits are mapped out: `before` and `after` are the file's PR diffs (--unified=0) over the
|
|
265
|
+
// reviewed and the current base, `baseDiff` the base's own change between them. A PR insertion
|
|
266
|
+
// that now sits just before or after lines the base inserted at the same point kept both sides
|
|
267
|
+
// of a conflict, so it is unchanged; a PR line that edits or replaces a base line is not.
|
|
268
|
+
// Large or binary patches fail closed (false).
|
|
269
|
+
export function ownLinesUnchanged(before, after, baseDiff = '') {
|
|
270
|
+
if (before === after) return true
|
|
271
|
+
if (before.length + after.length > MAX_FIX_DIFF_CHARS * 2) return false
|
|
272
|
+
if (/^(?:Binary files |GIT binary patch)/m.test(before + '\n' + after)) return false
|
|
273
|
+
const hunks = (diff) => [...diff.matchAll(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/gm)]
|
|
274
|
+
.map((m) => ({ oldStart: Number(m[1]), oldCount: Number(m[2] ?? 1), newStart: Number(m[3]), newCount: Number(m[4] ?? 1) }))
|
|
275
|
+
const base = hunks(baseDiff)
|
|
276
|
+
// A line of the current base, as a line of the reviewed base; null inside base-rewritten lines.
|
|
277
|
+
const toReviewed = (line, insertion) => {
|
|
278
|
+
let offset = 0
|
|
279
|
+
for (const h of base) {
|
|
280
|
+
if (insertion && h.oldCount === 0 && (line === h.newStart - 1 || line === h.newStart + h.newCount - 1)) return h.oldStart
|
|
281
|
+
const start = h.newCount === 0 ? h.newStart + 1 : h.newStart
|
|
282
|
+
if (line < start) break
|
|
283
|
+
if (h.newCount > 0 && line < start + h.newCount) return null
|
|
284
|
+
offset += h.oldCount - h.newCount
|
|
285
|
+
}
|
|
286
|
+
return line + offset
|
|
287
|
+
}
|
|
288
|
+
const rows = (diff, map) => {
|
|
289
|
+
const out = []
|
|
290
|
+
let hunk = null
|
|
291
|
+
let oldLine = 0
|
|
292
|
+
for (const line of diff.split('\n')) {
|
|
293
|
+
if (line.startsWith('diff --git ')) hunk = null
|
|
294
|
+
else if (line.startsWith('@@ ')) {
|
|
295
|
+
const m = /^@@ -(\d+)(?:,(\d+))?/.exec(line)
|
|
296
|
+
hunk = { insertion: Number(m[2] ?? 1) === 0 }
|
|
297
|
+
oldLine = Number(m[1])
|
|
298
|
+
// A reviewed hunk that comes back split around base lines is a change.
|
|
299
|
+
out.push('@@')
|
|
300
|
+
} else if (hunk && /^[+-]/.test(line)) {
|
|
301
|
+
const at = map(oldLine, hunk.insertion)
|
|
302
|
+
if (at === null) return null
|
|
303
|
+
out.push(`${at}\0${line}`)
|
|
304
|
+
if (line.startsWith('-')) oldLine++
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return out
|
|
308
|
+
}
|
|
309
|
+
const a = rows(before, (line) => line)
|
|
310
|
+
const b = rows(after, toReviewed)
|
|
311
|
+
return a !== null && b !== null && a.length === b.length && a.every((row, i) => row === b[i])
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function reachable(rev) {
|
|
315
|
+
try { git(['cat-file', '-e', `${rev}^{commit}`]); return true } catch { return false }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const lines = (text) => text.split('\n').filter(Boolean)
|
|
319
|
+
|
|
320
|
+
export function parseCliArgs(argv) {
|
|
321
|
+
const opts = { head: 'HEAD' }
|
|
322
|
+
for (let i = 0; i < argv.length; i++) {
|
|
323
|
+
const flag = argv[i]
|
|
324
|
+
if (flag === '--help' || flag === '-h') return { help: true }
|
|
325
|
+
if (!['--prior', '--base', '--head', '--write-skip'].includes(flag)) throw new RereviewScopeError(`unknown flag ${JSON.stringify(flag)}\n${USAGE}`)
|
|
326
|
+
const value = argv[++i]
|
|
327
|
+
if (value === undefined || value.startsWith('--')) throw new RereviewScopeError(`${flag} needs a value\n${USAGE}`)
|
|
328
|
+
opts[flag === '--write-skip' ? 'writeSkip' : flag.slice(2)] = value
|
|
329
|
+
}
|
|
330
|
+
if (!opts.prior || !opts.base) throw new RereviewScopeError(USAGE)
|
|
331
|
+
return opts
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export function rereviewScope({ prior, base, head = 'HEAD' }) {
|
|
335
|
+
const headSha = git(['rev-parse', head])
|
|
336
|
+
const mergeBase = git(['merge-base', base, headSha])
|
|
337
|
+
const currentPrFiles = lines(git(['diff', '--no-renames', '--name-only', `${mergeBase}...${headSha}`]))
|
|
338
|
+
const prLines = numstatLines(git(['diff', '--numstat', `${mergeBase}...${headSha}`]))
|
|
339
|
+
const round = (Number.isInteger(prior?.round) ? prior.round : 0) + 1
|
|
340
|
+
const priorHeadReachable = typeof prior?.head === 'string' && reachable(prior.head)
|
|
341
|
+
const priorBaseReachable = typeof prior?.mergeBase === 'string' && reachable(prior.mergeBase)
|
|
342
|
+
const patchId = prPatchId(mergeBase, headSha)
|
|
343
|
+
const patchFingerprint = prPatchFingerprint(mergeBase, headSha)
|
|
344
|
+
const priorPatchId = priorHeadReachable && priorBaseReachable ? prPatchId(prior.mergeBase, prior.head) : prior?.patchId
|
|
345
|
+
const priorPrFiles = priorHeadReachable && priorBaseReachable
|
|
346
|
+
? lines(git(['diff', '--no-renames', '--name-only', `${prior.mergeBase}...${prior.head}`])) : []
|
|
347
|
+
const prFiles = [...new Set([...currentPrFiles, ...priorPrFiles])]
|
|
348
|
+
const treeTouched = priorHeadReachable && prFiles.length
|
|
349
|
+
? lines(git(['diff', '--no-renames', '--name-only', prior.head, headSha, '--', ...prFiles])) : []
|
|
350
|
+
const samePatch = typeof priorPatchId === 'string' && patchId !== null && priorPatchId === patchId
|
|
351
|
+
&& (priorHeadReachable ? treeTouched.length === 0
|
|
352
|
+
: typeof prior?.patchFingerprint === 'string' && patchFingerprint === prior.patchFingerprint)
|
|
353
|
+
let baseMovedFiles = []
|
|
354
|
+
if (priorBaseReachable && prior.mergeBase !== mergeBase) {
|
|
355
|
+
baseMovedFiles = lines(git(['diff', '--no-renames', '--name-only', prior.mergeBase, mergeBase]))
|
|
356
|
+
}
|
|
357
|
+
const prSet = new Set(prFiles)
|
|
358
|
+
const overlap = baseMovedFiles.filter((file) => prSet.has(file))
|
|
359
|
+
// A PR file the base moved under had its own PR changes altered when its per-file patch
|
|
360
|
+
// differs from the reviewed one: a conflict resolution or a fix landed there too.
|
|
361
|
+
const conflictFiles = samePatch ? [] : overlap.filter((file) => !priorHeadReachable
|
|
362
|
+
|| prPatchId(prior.mergeBase, prior.head, [file]) !== prPatchId(mergeBase, headSha, [file]))
|
|
363
|
+
let touchedFiles = prFiles
|
|
364
|
+
let fixLines = prLines
|
|
365
|
+
let integrationLines = 0
|
|
366
|
+
if (samePatch) {
|
|
367
|
+
touchedFiles = []
|
|
368
|
+
fixLines = 0
|
|
369
|
+
} else if (priorHeadReachable && prFiles.length > 0) {
|
|
370
|
+
touchedFiles = treeTouched
|
|
371
|
+
// Lines the base alone changed are not fix lines. Compare overlapping PR patches separately.
|
|
372
|
+
const ownFiles = prFiles.filter((file) => !overlap.includes(file))
|
|
373
|
+
fixLines = ownFiles.length ? numstatLines(git(['diff', '--numstat', prior.head, headSha, '--', ...ownFiles])) : 0
|
|
374
|
+
if (priorBaseReachable) for (const file of conflictFiles) {
|
|
375
|
+
const before = git(['diff', '--no-renames', '--unified=0', prior.mergeBase, prior.head, '--', file])
|
|
376
|
+
const after = git(['diff', '--no-renames', '--unified=0', mergeBase, headSha, '--', file])
|
|
377
|
+
const baseDiff = git(['diff', '--no-renames', '--unified=0', prior.mergeBase, mergeBase, '--', file])
|
|
378
|
+
const impact = patchImpactLines(before, after, baseDiff)
|
|
379
|
+
if (impact === null) { integrationLines = null; break }
|
|
380
|
+
integrationLines += impact
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
const sameHead = priorHeadReachable && prior.head === headSha
|
|
384
|
+
// The base moved under PR files: are the PR's own lines there still the reviewed ones?
|
|
385
|
+
let ownUnchanged = false
|
|
386
|
+
if (!samePatch && priorHeadReachable && priorBaseReachable && overlap.length > 0 && fixLines === 0 && integrationLines !== null) {
|
|
387
|
+
ownUnchanged = overlap.every((file) => ownLinesUnchanged(
|
|
388
|
+
git(['diff', '--no-renames', '--unified=0', prior.mergeBase, prior.head, '--', file]),
|
|
389
|
+
git(['diff', '--no-renames', '--unified=0', mergeBase, headSha, '--', file]),
|
|
390
|
+
git(['diff', '--no-renames', '--unified=0', prior.mergeBase, mergeBase, '--', file])))
|
|
391
|
+
}
|
|
392
|
+
const decision = decideScope({ prior, round, prFiles, touchedFiles, baseMovedFiles, fixLines, integrationLines, prLines, priorHeadReachable, samePatch, sameHead, conflictFiles, baseKnown: priorBaseReachable, ownUnchanged })
|
|
393
|
+
const openFindings = (prior?.findings ?? []).filter(isBlocking)
|
|
394
|
+
const priorFixRound = prior?.fixRound ?? prior?.round
|
|
395
|
+
const fixRound = Number.isSafeInteger(priorFixRound) && priorFixRound >= 1
|
|
396
|
+
? priorFixRound + (reviewCompletionProblems(prior).length === 0 && openFindings.length > 0 ? 1 : 0) : null
|
|
397
|
+
const result = {
|
|
398
|
+
...decision,
|
|
399
|
+
fixRound,
|
|
400
|
+
head: headSha,
|
|
401
|
+
mergeBase,
|
|
402
|
+
patchId,
|
|
403
|
+
patchFingerprint,
|
|
404
|
+
samePatch,
|
|
405
|
+
priorHead: prior?.head ?? null,
|
|
406
|
+
baseMovedFiles,
|
|
407
|
+
baseDiffCommand: baseMovedFiles.length ? `git diff ${prior.mergeBase} ${mergeBase}` : null,
|
|
408
|
+
fixDiffCommand: null,
|
|
409
|
+
mergeDiffCommand: overlap.length ? `git diff ${prior.mergeBase} ${mergeBase} -- ${overlap.join(' ')}` : null,
|
|
410
|
+
openFindings,
|
|
411
|
+
}
|
|
412
|
+
if (decision.tier !== 'delta') return result
|
|
413
|
+
if (decision.touchedFiles.length === 0) {
|
|
414
|
+
// Nothing in the PR changed since the reviewed round: no fix diff to review.
|
|
415
|
+
return { ...result, fixDiff: '', sweepRecheck: [], changedSymbols: { names: [], anchors: [] }, callSites: { sites: [], truncated: false }, fixScan: { findings: [], leads: [] } }
|
|
416
|
+
}
|
|
417
|
+
// With the reviewed HEAD gone (samePatch), the only change is the merge diff.
|
|
418
|
+
const fixDiffArgs = samePatch
|
|
419
|
+
? ['diff', prior.mergeBase, mergeBase, '--', ...decision.touchedFiles]
|
|
420
|
+
: ['diff', prior.head, headSha, '--', ...decision.touchedFiles]
|
|
421
|
+
const fixDiff = git(fixDiffArgs)
|
|
422
|
+
const symbols = changedSymbols(fixDiff)
|
|
423
|
+
const scan = scanDiff(fixDiff)
|
|
424
|
+
return {
|
|
425
|
+
...result,
|
|
426
|
+
fixDiffCommand: `git ${fixDiffArgs.join(' ')}`,
|
|
427
|
+
fixDiff: fixDiff.length > MAX_FIX_DIFF_CHARS ? null : fixDiff,
|
|
428
|
+
sweepRecheck: sweepRecheck(prior, decision.touchedFiles),
|
|
429
|
+
changedSymbols: symbols,
|
|
430
|
+
callSites: callSites([...symbols.names, ...symbols.anchors], decision.carriedFiles, headSha),
|
|
431
|
+
fixScan: { findings: scan.findings, leads: scan.leads },
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// The result file a skip writes in place of a review: the previous approval, carried to this
|
|
436
|
+
// HEAD. It ran no checks of its own, found nothing new, and copies the coverage it carries.
|
|
437
|
+
export function skipRecord(prior, scope) {
|
|
438
|
+
if (scope.tier !== 'skip') throw new RereviewScopeError(`tier is ${scope.tier}, not skip: spawn the reviewer`)
|
|
439
|
+
return {
|
|
440
|
+
version: prior.version ?? 1,
|
|
441
|
+
...(prior.unit === undefined ? {} : { unit: prior.unit }),
|
|
442
|
+
round: scope.round,
|
|
443
|
+
fixRound: scope.fixRound,
|
|
444
|
+
head: scope.head,
|
|
445
|
+
mergeBase: scope.mergeBase,
|
|
446
|
+
patchId: scope.patchId,
|
|
447
|
+
patchFingerprint: scope.patchFingerprint,
|
|
448
|
+
tier: 'skip',
|
|
449
|
+
carriedFrom: prior.head,
|
|
450
|
+
fixLinesSinceFull: scope.fixLinesSinceFull,
|
|
451
|
+
oversize: false,
|
|
452
|
+
complete: true,
|
|
453
|
+
passes: prior.passes,
|
|
454
|
+
commands: [],
|
|
455
|
+
sweeps: prior.sweeps ?? [],
|
|
456
|
+
boundaries: prior.boundaries ?? [],
|
|
457
|
+
findings: [],
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Lines in the carried files that use a changed name, capped so a common name cannot flood it.
|
|
462
|
+
function callSites(terms, files, rev) {
|
|
463
|
+
const sites = []
|
|
464
|
+
let truncated = false
|
|
465
|
+
if (files.length === 0) return { sites, truncated }
|
|
466
|
+
for (const term of terms) {
|
|
467
|
+
const word = /^[A-Za-z_$][\w$]*$/.test(term)
|
|
468
|
+
let out = ''
|
|
469
|
+
try {
|
|
470
|
+
out = git(['grep', '-n', '-F', ...(word ? ['-w'] : []), '-e', term, rev, '--', ...files])
|
|
471
|
+
} catch { continue } // git grep exits 1 on no match
|
|
472
|
+
for (const line of lines(out)) {
|
|
473
|
+
const m = line.startsWith(`${rev}:`) ? line.slice(rev.length + 1).match(/^([^:]+):(\d+):(.*)$/) : null
|
|
474
|
+
if (!m) continue
|
|
475
|
+
if (sites.length >= MAX_CALL_SITES) { truncated = true; break }
|
|
476
|
+
sites.push({ term, file: m[1], line: Number(m[2]), text: m[3].trim().slice(0, 200) })
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return { sites, truncated }
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (isMainModule(import.meta.url)) {
|
|
483
|
+
try {
|
|
484
|
+
const opts = parseCliArgs(process.argv.slice(2))
|
|
485
|
+
if (opts.help) {
|
|
486
|
+
console.log(USAGE)
|
|
487
|
+
} else {
|
|
488
|
+
let prior
|
|
489
|
+
try { prior = JSON.parse(fs.readFileSync(opts.prior, 'utf8')) } catch (error) {
|
|
490
|
+
throw new RereviewScopeError(`cannot read previous result ${opts.prior}: ${error.message}`)
|
|
491
|
+
}
|
|
492
|
+
const scope = rereviewScope({ prior, base: opts.base, head: opts.head })
|
|
493
|
+
if (opts.writeSkip && scope.tier === 'skip') {
|
|
494
|
+
fs.writeFileSync(opts.writeSkip, `${JSON.stringify(skipRecord(prior, scope), null, 2)}\n`)
|
|
495
|
+
scope.skipRecord = opts.writeSkip
|
|
496
|
+
}
|
|
497
|
+
console.log(JSON.stringify(scope, null, 2))
|
|
498
|
+
}
|
|
499
|
+
} catch (error) {
|
|
500
|
+
console.error(`rereview-scope: ${error.message}`)
|
|
501
|
+
process.exitCode = 2
|
|
502
|
+
}
|
|
503
|
+
}
|