@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,151 @@
|
|
|
1
|
+
# The result
|
|
2
|
+
|
|
3
|
+
How to rate findings and, when a caller gives a result path, the file to write. Without a caller,
|
|
4
|
+
report in chat as [SKILL.md](../SKILL.md#5-run-the-checks-and-report-2-min) says.
|
|
5
|
+
|
|
6
|
+
## Severity
|
|
7
|
+
|
|
8
|
+
Only P0/P1 block. Pick the level by consequence, not by which pass found it. Never report P3.
|
|
9
|
+
|
|
10
|
+
| Level | Meaning |
|
|
11
|
+
|---|---|
|
|
12
|
+
| **P0** | Exploitable security, auth, tenancy, money, or data-loss defect on a reachable path. |
|
|
13
|
+
| **P1** | A contract break: an acceptance criterion unmet or wrong, required behavior wrong, a correctness bug with a concrete breaking input, a required repo standard or gate violated, a dishonest test cited as proof, or prose agents act on that contradicts the code. |
|
|
14
|
+
| **P2** | A real defect outside the contract: optional hardening, an untested branch whose failure is observable, scope creep, test tooling that hides no product bug. |
|
|
15
|
+
| **P3** | Not reported. Cleanup, naming, smells, cosmetics, architecture opinions, minor pre-existing issues: leave them out of the result and the chat report. |
|
|
16
|
+
|
|
17
|
+
A pre-existing defect the diff neither causes nor worsens is never P0/P1 for this change, however
|
|
18
|
+
serious; rate it P2 when serious (leave it out otherwise) and say in its summary how serious it is, so
|
|
19
|
+
its follow-up gets triaged.
|
|
20
|
+
|
|
21
|
+
## The result file
|
|
22
|
+
|
|
23
|
+
Write it to the path the caller gave. Callers decide the next step from severities alone, so do
|
|
24
|
+
not state a verdict. The file is incomplete when `complete` is not `true`, `commands` is empty (a
|
|
25
|
+
skip record excepted), `head` is not the HEAD you reviewed, an `executionIncident` is open, or a
|
|
26
|
+
P2 lacks its follow-up URL when the caller asked for follow-ups.
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"version": 1, "unit": "1201", "round": 1, "fixRound": 1, "head": "<reviewed sha>",
|
|
31
|
+
"complete": true, "executionIncident": null,
|
|
32
|
+
"mergeBase": "<merge-base sha from pr-context>", "patchId": "<patchId from pr-context>",
|
|
33
|
+
"patchFingerprint": "<patchFingerprint from pr-context>",
|
|
34
|
+
"tier": "full", "fixLinesSinceFull": 0, "oversize": false,
|
|
35
|
+
"commands": ["npm test -- src/billing", "npm run lint"],
|
|
36
|
+
"notRun": [{ "command": "npm run e2e:android", "error": "no emulator in this environment" }],
|
|
37
|
+
"passes": {
|
|
38
|
+
"spec": "done", "correctness": "done", "tests": "done", "standards": "done"
|
|
39
|
+
},
|
|
40
|
+
"sweeps": [
|
|
41
|
+
{
|
|
42
|
+
"rule": "every refund row carries currency, rate, and amount, or none of them",
|
|
43
|
+
"points": [
|
|
44
|
+
{ "location": "src/billing/refund.ts:30", "enforced": true },
|
|
45
|
+
{ "location": "src/export/refunds.ts:12", "enforced": false, "finding": "R1" }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"windows": [
|
|
50
|
+
{ "step": "SessionStore.logout", "location": "src/export/temp-file.ts:20",
|
|
51
|
+
"callers": ["settings button", "401 handler", "session-expiry timer"],
|
|
52
|
+
"coincides": ["app backgrounded", "offline"],
|
|
53
|
+
"outcomes": { "success": "file deleted", "error": "file kept (R4)", "timeout": "file kept (R4)" },
|
|
54
|
+
"outcome": "backgrounded: temp file kept until logout settles (R4)" }
|
|
55
|
+
],
|
|
56
|
+
"boundaries": [
|
|
57
|
+
{ "location": "src/billing/parse.ts:8", "pattern": "/^\\d+(\\.\\d{2})?$/",
|
|
58
|
+
"inputs": ["\"\"", "\"1.\"", "\"1.234\"", "\" 1.00\"", "\"-1.00\""], "outcome": "all rejected" }
|
|
59
|
+
],
|
|
60
|
+
"findings": [
|
|
61
|
+
{
|
|
62
|
+
"id": "R1", "severity": "P1", "pass": "correctness",
|
|
63
|
+
"summary": "Refund path converts USD→EUR with the inverted rate",
|
|
64
|
+
"file": "src/billing/refund.ts", "line": 42,
|
|
65
|
+
"trigger": "refund 100 USD at rate 0.9 returns 111.11 EUR, expected 90.00",
|
|
66
|
+
"rule": "every currency conversion multiplies by the source-to-target rate",
|
|
67
|
+
"paths": [
|
|
68
|
+
{ "path": "src/billing/refund.ts:42", "status": "open", "evidence": "divides by rate" },
|
|
69
|
+
{ "path": "src/billing/charge.ts:31", "status": "closed", "evidence": "convert() at :31" }
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "R2", "severity": "P2", "pass": "tests",
|
|
74
|
+
"summary": "refund rounding branch for zero-decimal currencies has no test",
|
|
75
|
+
"file": "src/billing/refund.ts", "line": 58,
|
|
76
|
+
"followUpUrl": "https://github.com/o/r/issues/9"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- `unit` is the caller's id for the change, when it gave one.
|
|
83
|
+
- `complete` is `true` only when every pass finished. Stopped part-way (interrupted, out of
|
|
84
|
+
context, or told to stop; a slow pass is not a reason): set it to `false`, set each pass you did
|
|
85
|
+
not finish to `unfinished`, keep every command you ran and every finding you wrote, and stop;
|
|
86
|
+
the caller resumes you or replaces the round. Never erase checks or invent findings to make it
|
|
87
|
+
look done.
|
|
88
|
+
- `notRun` lists each check the environment cannot run at all (no emulator, no device, no
|
|
89
|
+
credentials for a live service), with the command and its error verbatim; `[]` when none. It is
|
|
90
|
+
not a finding and does not make the review incomplete. A criterion whose proving test exists
|
|
91
|
+
but is listed here is not "unverified": say so in its spec row.
|
|
92
|
+
- `executionIncident` is for something that broke during this review and can be fixed (the test
|
|
93
|
+
database crashed, the runner lost its network): `{ "status": "open", "note": "<one line>" }`,
|
|
94
|
+
`null` when nothing broke. An open incident leaves the review incomplete until the caller fixes
|
|
95
|
+
it and you resume; then set `status: "resolved"`. Write no disposition document about it.
|
|
96
|
+
- `passes` holds, for a finished pass, `done`, `skipped: no spec found`,
|
|
97
|
+
`skipped: no standards found`, or
|
|
98
|
+
`skipped: not applicable: <reason>`. Any other value leaves the review incomplete. Never
|
|
99
|
+
`partial`, and never mark unfinished work skipped: a pass you did not finish is `unfinished`,
|
|
100
|
+
which correctly marks the whole review incomplete.
|
|
101
|
+
- `commands` lists the checks you ran against the code. Leave out this skill's update check and its
|
|
102
|
+
scripts (`pr-context.mjs`, `scan-diff.mjs`, `rereview-scope.mjs`): a caller reads a non-empty
|
|
103
|
+
list as proof the code was checked.
|
|
104
|
+
- `trigger` is required on P0/P1: the input, state, or sequence that breaks it.
|
|
105
|
+
- `rule` and `paths` are required on P0/P1, with at least one row `open`: the rule as one
|
|
106
|
+
sentence, and one row per path the diff adds, changes, or relies on (a writer, caller, sweep
|
|
107
|
+
place, or async cell), each `open` or `closed`, a closed row citing its guard's `file:line`.
|
|
108
|
+
A spec finding's `rule` is the criterion and its rows the places it must hold. When every row
|
|
109
|
+
is closed the finding is resolved: leave it out. A sweep's unenforced points are its finding's
|
|
110
|
+
open rows; `finding` names that id.
|
|
111
|
+
- `round` counts review attempts, skip records included, and names their files. `fixRound`
|
|
112
|
+
starts at `1`; on later rounds copy `rereview-scope.mjs`'s value, never your own. It is the
|
|
113
|
+
caller's fix counter: the tier never changes it.
|
|
114
|
+
- `tier` is `full` or `delta` (see [Review tiers](../SKILL.md#review-tiers)). Never write a
|
|
115
|
+
`scope` field.
|
|
116
|
+
- `mergeBase`, `patchId`, `patchFingerprint`, `tier`,
|
|
117
|
+
`fixLinesSinceFull` (`0` on a full round; the script's value on a delta), and `sweeps` (each
|
|
118
|
+
enforcement-point sweep: the rule and one row per place) let the next round run
|
|
119
|
+
`rereview-scope.mjs` and re-check the sweeps instead of redoing them. Take `mergeBase` and
|
|
120
|
+
`patchId` and `patchFingerprint` from `pr-context` on a full round and from
|
|
121
|
+
`rereview-scope.mjs` on a delta; `null` for an empty diff. The fingerprint also
|
|
122
|
+
preserves edit locations and binary bytes: patch-id alone cannot prove equivalence.
|
|
123
|
+
A reachable prior HEAD uses the actual PR-file tree diff; an unavailable prior HEAD
|
|
124
|
+
needs both matching identities, otherwise review in full. Empty `sweeps` is `[]`.
|
|
125
|
+
- On a delta, retain the tier decision (`reasons`, `integrationFiles`, `integrationLines`,
|
|
126
|
+
`baseMovedFiles`, and prior HEAD) so carry-forward approval names what was checked.
|
|
127
|
+
- `windows` lists each async step the change relies on, every caller of it you found (timers,
|
|
128
|
+
push events, expiry, and error handlers too), the events it was checked against, and for each
|
|
129
|
+
outcome (success, refusal, error, timeout) what the code did or the guard that rules the cell
|
|
130
|
+
out; `[]` when the diff has none.
|
|
131
|
+
- `boundaries` lists each regex, glob, parser, or validator the diff adds or changes with the
|
|
132
|
+
inputs tried against it; `[]` when the diff has none.
|
|
133
|
+
- On a re-review, keep a prior finding's `id` while its rule is broken anywhere, with every
|
|
134
|
+
row updated; a new witness of that rule is a new row, never a new id.
|
|
135
|
+
|
|
136
|
+
## The skip record
|
|
137
|
+
|
|
138
|
+
You never write one by hand. On a skip, `rereview-scope.mjs --write-skip <path>` writes it in
|
|
139
|
+
place of review findings, whether you or the caller ran the script: `tier: "skip"`,
|
|
140
|
+
`carriedFrom` (the HEAD whose approval it carries), the new HEAD and patch identities, `round`
|
|
141
|
+
(the previous plus one), `fixRound` and `fixLinesSinceFull` carried over, `complete: true`, the
|
|
142
|
+
previous `passes` and `sweeps`, `commands: []` and `findings: []`. It claims no checks; CI on its
|
|
143
|
+
HEAD is the proof. A caller confirms it against the history and the scripts rather than trusting
|
|
144
|
+
the file. The next round uses a skip record as its previous result like any other.
|
|
145
|
+
|
|
146
|
+
## Follow-ups
|
|
147
|
+
|
|
148
|
+
When the caller asks, file one issue per P2 before writing the file:
|
|
149
|
+
search for an existing one first, link it to the PR and the spec, and put its URL in
|
|
150
|
+
`followUpUrl`. When the caller says to file none, give each P2 its `file` and `line`; the
|
|
151
|
+
caller records it and writes its `dropboxId`. You change no code and push nothing.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
9
|
+
const WEEK_MS = 7 * DAY_MS;
|
|
10
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
|
|
12
|
+
function readJson(path, fallback = {}) {
|
|
13
|
+
try { return JSON.parse(readFileSync(path, 'utf8')); } catch { return fallback; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function frontmatterValue(text, key) {
|
|
17
|
+
const frontmatter = /^---\n([\s\S]*?)\n---/.exec(text)?.[1] ?? '';
|
|
18
|
+
const match = new RegExp('^' + key + ':\\s*([^\\n]+)$', 'm').exec(frontmatter);
|
|
19
|
+
return match?.[1].trim().replace(/^['"]|['"]$/g, '') ?? null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function repositoryOf(source) {
|
|
23
|
+
const value = String(source ?? '').trim();
|
|
24
|
+
const match = /^(?:git@github\.com:|https:\/\/github\.com\/)?([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+?)(?:\.git)?$/.exec(value);
|
|
25
|
+
return match?.[1] ?? null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function stableVersion(value) {
|
|
29
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(String(value ?? '').trim());
|
|
30
|
+
return match ? match.slice(1).map(Number) : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function newer(left, right) {
|
|
34
|
+
for (let index = 0; index < 3; index += 1) {
|
|
35
|
+
if (left[index] !== right[index]) return left[index] > right[index];
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function writeCache(path, value) {
|
|
41
|
+
try {
|
|
42
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
43
|
+
writeFileSync(path, JSON.stringify(value));
|
|
44
|
+
} catch { /* A read-only cache must not block skill use. */ }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function main(now = Date.now()) {
|
|
48
|
+
if (process.env.ONEABOVEIO_NO_UPDATE_CHECK) return;
|
|
49
|
+
const skill = readFileSync(join(here, 'SKILL.md'), 'utf8');
|
|
50
|
+
const name = frontmatterValue(skill, 'name');
|
|
51
|
+
const localVersion = stableVersion(frontmatterValue(skill, 'release-version'));
|
|
52
|
+
if (!name || !localVersion) return;
|
|
53
|
+
|
|
54
|
+
const lock = readJson(join(process.env.HOME || homedir(), '.agents', '.skill-lock.json'));
|
|
55
|
+
const entry = lock.skills?.[name];
|
|
56
|
+
const repository = repositoryOf(entry?.sourceUrl || entry?.source);
|
|
57
|
+
if (!repository) return;
|
|
58
|
+
|
|
59
|
+
const cacheRoot = process.env.XDG_CACHE_HOME || join(process.env.HOME || homedir(), '.cache');
|
|
60
|
+
const cachePath = join(cacheRoot, '1aboveio-skills', 'release-check.json');
|
|
61
|
+
const all = readJson(cachePath);
|
|
62
|
+
const cache = all[repository] && typeof all[repository] === 'object' ? all[repository] : {};
|
|
63
|
+
|
|
64
|
+
if (!cache.lastCheck || now - cache.lastCheck >= DAY_MS) {
|
|
65
|
+
const result = spawnSync('gh', ['api', 'repos/' + repository + '/releases/latest', '--jq', '.tag_name'], {
|
|
66
|
+
encoding: 'utf8',
|
|
67
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
68
|
+
timeout: 1500,
|
|
69
|
+
});
|
|
70
|
+
cache.lastCheck = now;
|
|
71
|
+
if (result.status === 0 && stableVersion(result.stdout)) cache.latestTag = result.stdout.trim();
|
|
72
|
+
else delete cache.latestTag;
|
|
73
|
+
all[repository] = cache;
|
|
74
|
+
writeCache(cachePath, all);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const latestVersion = stableVersion(cache.latestTag);
|
|
78
|
+
if (!latestVersion || !newer(latestVersion, localVersion)) return;
|
|
79
|
+
if (cache.notifiedTag === cache.latestTag && cache.notifiedAt && now - cache.notifiedAt < WEEK_MS) return;
|
|
80
|
+
|
|
81
|
+
cache.notifiedTag = cache.latestTag;
|
|
82
|
+
cache.notifiedAt = now;
|
|
83
|
+
all[repository] = cache;
|
|
84
|
+
writeCache(cachePath, all);
|
|
85
|
+
const command = `npx skills@1.5.23 add '${repository}#${cache.latestTag}' --global --agent universal claude-code --skill ${name} --yes`;
|
|
86
|
+
process.stdout.write(
|
|
87
|
+
`UPDATE_AVAILABLE: A newer 1AboveIO skills release (${cache.latestTag}) is available; this skill is `
|
|
88
|
+
+ `v${localVersion.join('.')}. Ask once whether to refresh ${name}. On approval run \`${command}\`. `
|
|
89
|
+
+ 'The refreshed instructions apply next session. Either way, continue the current task and do not ask again this session.\n',
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try { main(); } catch { /* Update checks are advisory and always fail silent. */ }
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Establish the review SUBJECT correctly, every time: the net three-dot diff from
|
|
2
|
+
// the merge-base, the changed files, and the commit list (for the history scan).
|
|
3
|
+
// Pure git — language-agnostic. Pure parsers are unit-tested; git calls live in
|
|
4
|
+
// the CLI. Removes the classic diff-discipline footgun (two-dot vs three-dot, wrong
|
|
5
|
+
// base) so the reviewer reasons over the right change-set.
|
|
6
|
+
//
|
|
7
|
+
// node pr-context.mjs --base main [--head HEAD] [--head-ref <branch-name>]
|
|
8
|
+
// # prints JSON review context
|
|
9
|
+
//
|
|
10
|
+
// The range it emits is `<merge-base>...HEAD` (three-dot = what would merge), which
|
|
11
|
+
// is what references/passes.md requires.
|
|
12
|
+
//
|
|
13
|
+
// PROMOTION SIGNAL. `promotion: true` marks a release/integration branch being merged
|
|
14
|
+
// into production (review as a release: fast-forward gate + readiness checklist, not a
|
|
15
|
+
// line-by-line re-review). It requires BOTH halves: the BASE is a production branch
|
|
16
|
+
// (main/master/production/prod) AND the HEAD is a recognized integration/release branch
|
|
17
|
+
// (dev, develop, release/*, hotfix/*, staging, staging/*). A base check alone is wrong
|
|
18
|
+
// in a trunk-based repo, where every feature PR targets `main` — those are feature PRs,
|
|
19
|
+
// not promotions (see issue #392).
|
|
20
|
+
//
|
|
21
|
+
// The head is classified by its BRANCH NAME. `--head` is a rev (default HEAD); the name
|
|
22
|
+
// is resolved from it (`git rev-parse --abbrev-ref`), or you may pass it explicitly with
|
|
23
|
+
// `--head-ref`. When the name cannot be resolved (a detached HEAD or a bare SHA — nothing
|
|
24
|
+
// to classify), the SAFE DEFAULT is `promotion: false`: treating a real promotion as a
|
|
25
|
+
// feature PR just runs the normal review; the reverse (issue #392's bug) mis-routes it.
|
|
26
|
+
|
|
27
|
+
import { execFileSync } from 'node:child_process'
|
|
28
|
+
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
29
|
+
import { prPatchId, prPatchFingerprint } from './rereview-scope.mjs'
|
|
30
|
+
|
|
31
|
+
// ---- pure core ----
|
|
32
|
+
|
|
33
|
+
export function threeDotRange(base, head = 'HEAD') {
|
|
34
|
+
return `${base}...${head}`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Parse `git diff --name-status <range>` → [{status, path}] (handles rename "R100\told\tnew").
|
|
38
|
+
export function parseNameStatus(text) {
|
|
39
|
+
return (text || '').split(/\r?\n/).filter(Boolean).map((line) => {
|
|
40
|
+
const parts = line.split('\t')
|
|
41
|
+
const status = parts[0]
|
|
42
|
+
const path = status.startsWith('R') || status.startsWith('C') ? parts[parts.length - 1] : parts[1]
|
|
43
|
+
return { status, path }
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Parse `git log --oneline <base>..HEAD` → [{sha, subject}] (two-dot here is correct:
|
|
48
|
+
// the commits unique to the PR head).
|
|
49
|
+
export function parseLog(text) {
|
|
50
|
+
return (text || '').split(/\r?\n/).filter(Boolean).map((line) => {
|
|
51
|
+
const sp = line.indexOf(' ')
|
|
52
|
+
return sp === -1 ? { sha: line, subject: '' } : { sha: line.slice(0, sp), subject: line.slice(sp + 1) }
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// A promotion (e.g. dev→main) must FAST-FORWARD: the base must be an ancestor of
|
|
57
|
+
// HEAD, i.e. no commits live on base that HEAD lacks. A non-empty list = base has
|
|
58
|
+
// commits (usually hotfixes) the promotion would REVERT — hold and back-merge first.
|
|
59
|
+
export function fastForwardable(commitsOnBaseNotInHead) {
|
|
60
|
+
return (commitsOnBaseNotInHead || []).length === 0
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// A promotion TARGET: the base is a production branch. Necessary but NOT sufficient —
|
|
64
|
+
// a promotion also needs an integration/release HEAD (see isPromotion). Keying on this
|
|
65
|
+
// alone flags every feature PR in a trunk-based repo as a promotion (issue #392).
|
|
66
|
+
export function isPromotionTarget(baseRef) {
|
|
67
|
+
return /(^|\/)(main|master|production|prod)$/.test(baseRef || '')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Conventional remote names recognized in the SHORT remote-tracking form
|
|
71
|
+
// (`origin/dev`). The full `refs/remotes/<remote>/…` form strips any remote segment
|
|
72
|
+
// because the namespace is explicit and unambiguous; the short form is ambiguous with
|
|
73
|
+
// an ordinary namespaced branch (`jsmith/dev`), so we only strip a KNOWN remote — never
|
|
74
|
+
// an arbitrary first segment. This is normalization, not part of the integration
|
|
75
|
+
// allowlist.
|
|
76
|
+
const KNOWN_REMOTES = ['origin', 'upstream']
|
|
77
|
+
|
|
78
|
+
// Normalize a head ref to a bare branch name by stripping ONLY known ref prefixes, so
|
|
79
|
+
// the integration/release name (if any) lands at the START of the string. Handles the
|
|
80
|
+
// three git ref shapes: `refs/heads/<name>`, `refs/remotes/<remote>/<name>`, and the
|
|
81
|
+
// short remote-tracking `<known-remote>/<name>`. It NEVER strips an arbitrary leading
|
|
82
|
+
// path segment — that is exactly the any-prefix hole (issue #392) this closes: a
|
|
83
|
+
// namespaced feature branch like `feature/release/notes` or `jsmith/dev` keeps its
|
|
84
|
+
// namespace and so cannot masquerade as an integration branch.
|
|
85
|
+
export function normalizeHeadName(headRef) {
|
|
86
|
+
const name = headRef || ''
|
|
87
|
+
if (name.startsWith('refs/heads/')) return name.slice('refs/heads/'.length)
|
|
88
|
+
if (name.startsWith('refs/remotes/')) {
|
|
89
|
+
// drop `refs/remotes/` + exactly ONE remote segment
|
|
90
|
+
return name.slice('refs/remotes/'.length).replace(/^[^/]+\//, '')
|
|
91
|
+
}
|
|
92
|
+
for (const remote of KNOWN_REMOTES) {
|
|
93
|
+
if (name.startsWith(`${remote}/`)) return name.slice(remote.length + 1)
|
|
94
|
+
}
|
|
95
|
+
return name
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// A promotion HEAD: an integration or release branch, by NAME. A small, documented
|
|
99
|
+
// allowlist of integration/release shapes — dev/develop, staging, and release/hotfix/
|
|
100
|
+
// staging/*. After normalizing away known ref prefixes (`refs/heads/`, `refs/remotes/`,
|
|
101
|
+
// and short `origin/`-style remotes), the integration name is matched ANCHORED AT THE
|
|
102
|
+
// START (`^`): the exact whole-name shapes (`dev`/`develop`/`staging`) and the path
|
|
103
|
+
// shapes (`release/`/`hotfix/`/`staging/`). The name must OPEN the branch, never be
|
|
104
|
+
// buried under a namespace — so `origin/dev` and `refs/heads/develop` resolve, but a
|
|
105
|
+
// namespaced feature branch like `feature/release/notes` or `jsmith/dev` does not.
|
|
106
|
+
// Anything else (the common case: an ordinary feature branch, or an unresolvable bare
|
|
107
|
+
// SHA) → false.
|
|
108
|
+
export function isIntegrationBranch(headRef) {
|
|
109
|
+
const name = normalizeHeadName(headRef)
|
|
110
|
+
// exact whole-name integration branches: dev, develop, staging
|
|
111
|
+
if (/^(dev|develop|staging)$/.test(name)) return true
|
|
112
|
+
// release-family branches with a version/name suffix, name at the START: release/*, hotfix/*, staging/*
|
|
113
|
+
if (/^(release|hotfix|staging)\//.test(name)) return true
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// A PROMOTION = a production BASE receiving an integration/release HEAD. Both halves
|
|
118
|
+
// required. Review it as a release (fast-forward gate + readiness checklist), not a
|
|
119
|
+
// line-by-line re-review of feature code already merged & green on the integration
|
|
120
|
+
// branch. An unresolvable head (bare SHA → not integration-shaped) yields false, the
|
|
121
|
+
// documented safe default.
|
|
122
|
+
export function isPromotion(baseRef, headRef) {
|
|
123
|
+
return isPromotionTarget(baseRef) && isIntegrationBranch(headRef)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// The reviewer-facing note for the emitted context. Pure so the promotion branches are
|
|
127
|
+
// unit-testable without git. The PROMOTION + NOT fast-forwardable hold-and-back-merge
|
|
128
|
+
// guidance is unchanged — only the trigger (isPromotion) is corrected.
|
|
129
|
+
export function reviewNote({ promotion, fastForwardable: ff, base, head, commitsOnBaseNotInHead }) {
|
|
130
|
+
if (promotion && !ff) {
|
|
131
|
+
const n = (commitsOnBaseNotInHead || []).length
|
|
132
|
+
return `PROMOTION + NOT fast-forwardable: ${base} has ${n} commit(s) not in ${head} (likely hotfixes). HOLD — back-merge ${base} → ${head} first; promoting would revert them. Then apply the release-readiness checklist (migrations/secrets/flag-defaults/version/rollback).`
|
|
133
|
+
}
|
|
134
|
+
if (promotion) {
|
|
135
|
+
return 'PROMOTION (fast-forwardable): do not re-review feature code already merged & green on the integration branch. Run only the release-readiness checklist on the content: migrations/backfills, secrets & config, feature-flag defaults, version/changelog, rollback.'
|
|
136
|
+
}
|
|
137
|
+
return 'Review the NET diff (range above), not commit-by-commit. Scope findings to what this range introduces; pre-existing issues (present at mergeBase) are notes, not blockers. Scan `commits` for secrets added-then-removed / unsafe intermediate states.'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---- CLI ----
|
|
141
|
+
|
|
142
|
+
function git(args) {
|
|
143
|
+
return execFileSync('git', args, { encoding: 'utf8' }).trim()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function parseArgs(argv) {
|
|
147
|
+
const f = { head: 'HEAD' }
|
|
148
|
+
for (let i = 2; i < argv.length; i++) {
|
|
149
|
+
const a = argv[i]
|
|
150
|
+
if (a.startsWith('--')) f[a.slice(2)] = argv[++i]
|
|
151
|
+
}
|
|
152
|
+
return f
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Resolve the head's symbolic BRANCH NAME (what isIntegrationBranch classifies), or null
|
|
156
|
+
// when there is nothing to classify. Prefer an explicit --head-ref; otherwise ask git for
|
|
157
|
+
// the symbolic name of --head. A detached HEAD (`git rev-parse --abbrev-ref` → "HEAD") or a
|
|
158
|
+
// bare SHA (echoed back unchanged) has no branch name → null → promotion defaults false.
|
|
159
|
+
function resolveHeadName(a) {
|
|
160
|
+
if (a['head-ref']) return a['head-ref']
|
|
161
|
+
const head = a.head || 'HEAD'
|
|
162
|
+
let name
|
|
163
|
+
try {
|
|
164
|
+
name = git(['rev-parse', '--abbrev-ref', head])
|
|
165
|
+
} catch {
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
if (!name || name === 'HEAD' || /^[0-9a-f]{7,40}$/i.test(name)) return null
|
|
169
|
+
return name
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function main() {
|
|
173
|
+
const a = parseArgs(process.argv)
|
|
174
|
+
if (!a.base) {
|
|
175
|
+
console.error('usage: pr-context.mjs --base <target-branch-or-ref> [--head HEAD] [--head-ref <branch-name>]')
|
|
176
|
+
process.exit(2)
|
|
177
|
+
}
|
|
178
|
+
const base = git(['merge-base', a.base, a.head])
|
|
179
|
+
const range = threeDotRange(base, a.head)
|
|
180
|
+
const files = parseNameStatus(git(['diff', '--name-status', range]))
|
|
181
|
+
const commits = parseLog(git(['log', '--oneline', `${base}..${a.head}`]))
|
|
182
|
+
const diffstat = git(['diff', '--shortstat', range])
|
|
183
|
+
// commits on the base that HEAD lacks (in base, not in head) — the fast-forward / drift signal
|
|
184
|
+
const commitsOnBaseNotInHead = parseLog(git(['log', '--oneline', `${a.head}..${a.base}`]))
|
|
185
|
+
const ff = fastForwardable(commitsOnBaseNotInHead)
|
|
186
|
+
// Promotion requires BOTH a production base AND an integration/release head — a base
|
|
187
|
+
// check alone flags every feature→main PR (issue #392). headRef is the resolved head
|
|
188
|
+
// branch name (null when unresolvable → not integration-shaped → promotion false).
|
|
189
|
+
const headRef = resolveHeadName(a)
|
|
190
|
+
const promotion = isPromotion(a.base, headRef)
|
|
191
|
+
const ctx = {
|
|
192
|
+
targetRef: a.base,
|
|
193
|
+
headRef,
|
|
194
|
+
mergeBase: base,
|
|
195
|
+
// Write it into the result: a later round uses it to reuse this review across a
|
|
196
|
+
// content-equivalent rebase (rereview-scope.mjs).
|
|
197
|
+
patchId: prPatchId(base, a.head),
|
|
198
|
+
patchFingerprint: prPatchFingerprint(base, a.head),
|
|
199
|
+
range,
|
|
200
|
+
diffCommand: `git diff ${range}`,
|
|
201
|
+
changedFiles: files,
|
|
202
|
+
commits,
|
|
203
|
+
diffstat,
|
|
204
|
+
promotion,
|
|
205
|
+
fastForwardable: ff,
|
|
206
|
+
commitsOnBaseNotInHead,
|
|
207
|
+
note: reviewNote({ promotion, fastForwardable: ff, base: a.base, head: a.head, commitsOnBaseNotInHead }),
|
|
208
|
+
}
|
|
209
|
+
console.log(JSON.stringify(ctx, null, 2))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (isMainModule(import.meta.url)) main()
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { threeDotRange, parseNameStatus, parseLog, fastForwardable, isPromotionTarget, isIntegrationBranch, isPromotion, reviewNote, normalizeHeadName } from './pr-context.mjs'
|
|
4
|
+
|
|
5
|
+
test('threeDotRange uses three dots (the merge diff, not two-dot)', () => {
|
|
6
|
+
assert.equal(threeDotRange('abc123'), 'abc123...HEAD')
|
|
7
|
+
assert.equal(threeDotRange('abc', 'feat'), 'abc...feat')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
test('parseNameStatus handles add/modify/delete and rename', () => {
|
|
11
|
+
const text = ['M\tsrc/a.ts', 'A\tsrc/new.ts', 'D\tsrc/old.ts', 'R100\tsrc/from.ts\tsrc/to.ts'].join('\n')
|
|
12
|
+
assert.deepEqual(parseNameStatus(text), [
|
|
13
|
+
{ status: 'M', path: 'src/a.ts' },
|
|
14
|
+
{ status: 'A', path: 'src/new.ts' },
|
|
15
|
+
{ status: 'D', path: 'src/old.ts' },
|
|
16
|
+
{ status: 'R100', path: 'src/to.ts' },
|
|
17
|
+
])
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('parseNameStatus empty → []', () => {
|
|
21
|
+
assert.deepEqual(parseNameStatus(''), [])
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('parseLog splits sha + subject', () => {
|
|
25
|
+
const text = '1a2b3c add export\n4d5e6f fix expired coupon'
|
|
26
|
+
assert.deepEqual(parseLog(text), [
|
|
27
|
+
{ sha: '1a2b3c', subject: 'add export' },
|
|
28
|
+
{ sha: '4d5e6f', subject: 'fix expired coupon' },
|
|
29
|
+
])
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('fastForwardable: empty = FF possible; non-empty (base has commits head lacks) = not FF', () => {
|
|
33
|
+
assert.equal(fastForwardable([]), true)
|
|
34
|
+
assert.equal(fastForwardable([{ sha: 'h0tf1x', subject: 'hotfix prod' }]), false)
|
|
35
|
+
assert.equal(fastForwardable(undefined), true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('isPromotionTarget: production branches only (the base half of a promotion)', () => {
|
|
39
|
+
assert.equal(isPromotionTarget('main'), true)
|
|
40
|
+
assert.equal(isPromotionTarget('master'), true)
|
|
41
|
+
assert.equal(isPromotionTarget('production'), true)
|
|
42
|
+
assert.equal(isPromotionTarget('origin/main'), true)
|
|
43
|
+
assert.equal(isPromotionTarget('dev'), false)
|
|
44
|
+
assert.equal(isPromotionTarget('feature/x'), false)
|
|
45
|
+
assert.equal(isPromotionTarget('release/1.2'), false)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('isIntegrationBranch: only integration/release-shaped heads (the head half of a promotion)', () => {
|
|
49
|
+
// integration branches
|
|
50
|
+
assert.equal(isIntegrationBranch('dev'), true)
|
|
51
|
+
assert.equal(isIntegrationBranch('develop'), true)
|
|
52
|
+
assert.equal(isIntegrationBranch('origin/dev'), true)
|
|
53
|
+
assert.equal(isIntegrationBranch('refs/heads/develop'), true)
|
|
54
|
+
// release / hotfix / staging shapes
|
|
55
|
+
assert.equal(isIntegrationBranch('release/1.4'), true)
|
|
56
|
+
assert.equal(isIntegrationBranch('release/2.0.0'), true)
|
|
57
|
+
assert.equal(isIntegrationBranch('hotfix/urgent-fix'), true)
|
|
58
|
+
assert.equal(isIntegrationBranch('staging'), true)
|
|
59
|
+
assert.equal(isIntegrationBranch('staging/eu'), true)
|
|
60
|
+
assert.equal(isIntegrationBranch('origin/release/1.4'), true)
|
|
61
|
+
// ordinary feature branches — NOT integration
|
|
62
|
+
assert.equal(isIntegrationBranch('feature/x'), false)
|
|
63
|
+
assert.equal(isIntegrationBranch('chore/388-doc-code-prose-audit'), false)
|
|
64
|
+
assert.equal(isIntegrationBranch('issue-392-promotion-heuristic'), false)
|
|
65
|
+
assert.equal(isIntegrationBranch('main'), false)
|
|
66
|
+
assert.equal(isIntegrationBranch('develop-tweaks'), false) // not exactly `develop`
|
|
67
|
+
assert.equal(isIntegrationBranch('feature/release-notes'), false) // `release` not its own segment
|
|
68
|
+
// unresolvable head (a bare SHA, or empty) — NOT integration → safe default
|
|
69
|
+
assert.equal(isIntegrationBranch('a1b2c3d'), false)
|
|
70
|
+
assert.equal(isIntegrationBranch(''), false)
|
|
71
|
+
assert.equal(isIntegrationBranch(undefined), false)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('isPromotion: true ONLY when base is production AND head is integration/release-shaped', () => {
|
|
75
|
+
// the ~15x false-positive this fixes: a feature branch → main is NOT a promotion
|
|
76
|
+
assert.equal(isPromotion('main', 'chore/388-doc-code-prose-audit'), false)
|
|
77
|
+
assert.equal(isPromotion('main', 'feature/x'), false)
|
|
78
|
+
assert.equal(isPromotion('main', 'issue-392-promotion-heuristic'), false)
|
|
79
|
+
// genuine promotions: integration/release branch → production
|
|
80
|
+
assert.equal(isPromotion('main', 'dev'), true)
|
|
81
|
+
assert.equal(isPromotion('main', 'release/1.4'), true)
|
|
82
|
+
assert.equal(isPromotion('main', 'hotfix/x'), true)
|
|
83
|
+
assert.equal(isPromotion('master', 'develop'), true)
|
|
84
|
+
assert.equal(isPromotion('origin/main', 'origin/dev'), true)
|
|
85
|
+
// base is not a production branch → never a promotion, even from an integration head
|
|
86
|
+
assert.equal(isPromotion('dev', 'feature/x'), false)
|
|
87
|
+
assert.equal(isPromotion('release/1.4', 'dev'), false)
|
|
88
|
+
// unresolvable head (bare SHA / empty) → false (documented safe default)
|
|
89
|
+
assert.equal(isPromotion('main', 'a1b2c3d'), false)
|
|
90
|
+
assert.equal(isPromotion('main', ''), false)
|
|
91
|
+
assert.equal(isPromotion('main', undefined), false)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('normalizeHeadName strips ONLY known ref prefixes — never an arbitrary leading segment', () => {
|
|
95
|
+
// known ref prefixes → stripped to the bare name
|
|
96
|
+
assert.equal(normalizeHeadName('refs/heads/develop'), 'develop')
|
|
97
|
+
assert.equal(normalizeHeadName('refs/remotes/origin/release/1.4'), 'release/1.4')
|
|
98
|
+
assert.equal(normalizeHeadName('origin/dev'), 'dev')
|
|
99
|
+
assert.equal(normalizeHeadName('origin/release/1.4'), 'release/1.4')
|
|
100
|
+
assert.equal(normalizeHeadName('upstream/staging'), 'staging')
|
|
101
|
+
// NOT a known prefix → left intact (the any-prefix hole this closes)
|
|
102
|
+
assert.equal(normalizeHeadName('jsmith/dev'), 'jsmith/dev')
|
|
103
|
+
assert.equal(normalizeHeadName('feature/release/notes'), 'feature/release/notes')
|
|
104
|
+
assert.equal(normalizeHeadName('team/staging/eu'), 'team/staging/eu')
|
|
105
|
+
// plain names pass through
|
|
106
|
+
assert.equal(normalizeHeadName('dev'), 'dev')
|
|
107
|
+
assert.equal(normalizeHeadName('release/1.4'), 'release/1.4')
|
|
108
|
+
assert.equal(normalizeHeadName(''), '')
|
|
109
|
+
assert.equal(normalizeHeadName(undefined), '')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// LEFT-BOUNDARY REGRESSION (issue #392, fix round): the integration/release name must
|
|
113
|
+
// open the branch (after ref-prefix stripping), never be buried under a namespace. A
|
|
114
|
+
// nested-prefix feature branch is an ordinary feature PR, not a promotion — the unsafe
|
|
115
|
+
// direction if mis-classified. Removing the `^`/normalization makes these go RED.
|
|
116
|
+
test('isIntegrationBranch: nested-prefix feature branches are NOT integration (left-boundary hole)', () => {
|
|
117
|
+
// line-79 (release/hotfix/staging path) hole
|
|
118
|
+
assert.equal(isIntegrationBranch('feature/release/notes'), false)
|
|
119
|
+
assert.equal(isIntegrationBranch('feature/hotfix/x'), false)
|
|
120
|
+
assert.equal(isIntegrationBranch('team/staging/eu'), false)
|
|
121
|
+
// line-77 (exact dev/develop/staging) hole
|
|
122
|
+
assert.equal(isIntegrationBranch('jsmith/dev'), false)
|
|
123
|
+
assert.equal(isIntegrationBranch('alice/develop'), false)
|
|
124
|
+
assert.equal(isIntegrationBranch('wip/staging'), false)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('isIntegrationBranch: supported ref prefixes still resolve to TRUE after normalization', () => {
|
|
128
|
+
assert.equal(isIntegrationBranch('origin/dev'), true)
|
|
129
|
+
assert.equal(isIntegrationBranch('refs/heads/develop'), true)
|
|
130
|
+
assert.equal(isIntegrationBranch('refs/remotes/origin/release/1.4'), true)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test('isPromotion: nested-prefix feature branches → main are NOT promotions (left-boundary hole)', () => {
|
|
134
|
+
// these all classified promotion=true before the anchor fix (the fail-open direction)
|
|
135
|
+
assert.equal(isPromotion('main', 'feature/release/notes'), false)
|
|
136
|
+
assert.equal(isPromotion('main', 'feature/hotfix/x'), false)
|
|
137
|
+
assert.equal(isPromotion('main', 'team/staging/eu'), false)
|
|
138
|
+
assert.equal(isPromotion('main', 'jsmith/dev'), false)
|
|
139
|
+
assert.equal(isPromotion('main', 'alice/develop'), false)
|
|
140
|
+
assert.equal(isPromotion('main', 'wip/staging'), false)
|
|
141
|
+
// supported prefixes remain genuine promotions
|
|
142
|
+
assert.equal(isPromotion('main', 'refs/heads/develop'), true)
|
|
143
|
+
assert.equal(isPromotion('main', 'refs/remotes/origin/release/1.4'), true)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
test('reviewNote: PROMOTION + NOT fast-forwardable note still fires for a genuine promotion that is not FF', () => {
|
|
147
|
+
const note = reviewNote({
|
|
148
|
+
promotion: true,
|
|
149
|
+
fastForwardable: false,
|
|
150
|
+
base: 'main',
|
|
151
|
+
head: 'release/1.4',
|
|
152
|
+
commitsOnBaseNotInHead: [{ sha: 'h0tf1x', subject: 'hotfix prod' }],
|
|
153
|
+
})
|
|
154
|
+
assert.match(note, /PROMOTION \+ NOT fast-forwardable/)
|
|
155
|
+
assert.match(note, /main has 1 commit\(s\) not in release\/1\.4/)
|
|
156
|
+
assert.match(note, /HOLD/)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('reviewNote: fast-forwardable promotion → release-readiness note (not a re-review)', () => {
|
|
160
|
+
const note = reviewNote({ promotion: true, fastForwardable: true, base: 'main', head: 'dev', commitsOnBaseNotInHead: [] })
|
|
161
|
+
assert.match(note, /PROMOTION \(fast-forwardable\)/)
|
|
162
|
+
assert.doesNotMatch(note, /NOT fast-forwardable/)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test('reviewNote: not a promotion → review the NET diff (the common feature-PR path)', () => {
|
|
166
|
+
const note = reviewNote({ promotion: false, fastForwardable: true, base: 'main', head: 'feature/x', commitsOnBaseNotInHead: [] })
|
|
167
|
+
assert.match(note, /Review the NET diff/)
|
|
168
|
+
})
|