@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,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github-flow
|
|
3
|
+
description: "Deliver a change after the commit: push, open a PR, wait for checks, and merge to main through the repo's flow (direct push, pull request, or merge queue). Use whenever you commit or finish a change, when CONTRIBUTING.md has a Delivery section, and for asks like 'commit this', 'push it', 'open a PR', 'ship it', 'land it', 'get it merged'. Also: declare a repo's delivery flow, or write the CI conventions and Delivery section into CONTRIBUTING.md on request. NOT for writing workflow YAML (github-actions), Mergify config or a stuck queued PR (mergify), cutting a release (resolve-release), or PRs that resolve-issues or rush-issues deliver."
|
|
4
|
+
release-version: 0.36.0
|
|
5
|
+
---
|
|
6
|
+
**Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
|
|
7
|
+
# GitHub Flow
|
|
8
|
+
|
|
9
|
+
Take a committed change to done. Set `SKILL_DIR` to the directory you read this file from.
|
|
10
|
+
|
|
11
|
+
## Routing index
|
|
12
|
+
|
|
13
|
+
| You are… | Go to |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Just committed, or finished a change | [Deliver](#deliver) |
|
|
16
|
+
| Asked to push, open a PR, or merge | [Deliver](#deliver) |
|
|
17
|
+
| A check on your PR is red | [Fix a red check](#fix-a-red-check) |
|
|
18
|
+
| A merge waits on a review or approval | [Stop at a human gate](#stop-at-a-human-gate) |
|
|
19
|
+
| A queued PR is stuck or dequeued | the `mergify` skill |
|
|
20
|
+
| Asked to write the CI rules or delivery flow into the repo | [Persist to CONTRIBUTING.md](#persist-to-contributingmd) |
|
|
21
|
+
|
|
22
|
+
## Deliver
|
|
23
|
+
|
|
24
|
+
1. Read the flow:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
node "$SKILL_DIR/scripts/flow.mjs"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
It prints `source` (`declared` or `detected`), `flow`, `done`, `mergeMethod`, `queue`,
|
|
31
|
+
`autoMerge`, the default `branch`, and `evidence`.
|
|
32
|
+
2. Decide how far to go:
|
|
33
|
+
- `source: declared` and `done: merged`: run the whole flow. Do not stop at the commit.
|
|
34
|
+
- The user asked in this session to push, open a PR, or merge: run the flow up to what they asked.
|
|
35
|
+
- Otherwise: stop after the commit and ask once, naming the flow and its evidence:
|
|
36
|
+
"Push and deliver through the `<flow>` flow?" Offer to declare the flow
|
|
37
|
+
([Persist](#persist-to-contributingmd)). Never end the session silently with unpushed commits.
|
|
38
|
+
3. Run the steps for the flow: [direct](#flow-direct), [pull-request](#flow-pull-request),
|
|
39
|
+
or [merge-queue](#flow-merge-queue).
|
|
40
|
+
4. Report the result: the pushed SHA, the PR URL and merge commit, or where it stopped and why.
|
|
41
|
+
|
|
42
|
+
Commit only the files of this change. Leave unrelated working-tree changes alone.
|
|
43
|
+
|
|
44
|
+
## Flow: direct
|
|
45
|
+
|
|
46
|
+
1. Run the repo's local checks (the test, lint, and build commands `CONTRIBUTING.md` or `AGENTS.md`
|
|
47
|
+
names). Fix failures before pushing.
|
|
48
|
+
2. `git pull --rebase origin <branch>`. Rerun the checks if the rebase brought in changes.
|
|
49
|
+
3. `git push origin HEAD:<branch>`. On a rejected push, pull with rebase and push once more; then report.
|
|
50
|
+
4. Never force-push.
|
|
51
|
+
|
|
52
|
+
## Flow: pull-request
|
|
53
|
+
|
|
54
|
+
1. If you committed on the default branch, move the commits to a branch: `git fetch origin`,
|
|
55
|
+
`git switch -c <type>/<short-slug>`, then `git branch -f <branch> origin/<branch>`.
|
|
56
|
+
2. `git push -u origin HEAD`.
|
|
57
|
+
3. `gh pr create --fill`, ready for review, not draft. Add `Closes #<n>` when the change resolves an issue.
|
|
58
|
+
- Stack repo (`mergify-hooks/` in the git hooks dir; the pre-push hook says "Use 'mergify stack
|
|
59
|
+
push'"): replace steps 2–3 with the `mergify` skill's `scripts/stack-push.mjs`. Put
|
|
60
|
+
`Closes #<n>` in the commit message. Never `--no-verify`.
|
|
61
|
+
4. Wait for the checks: `gh pr checks --watch --required --fail-fast`.
|
|
62
|
+
- "no required checks": run it again without `--required`.
|
|
63
|
+
- "no checks reported": wait 30 seconds and retry; after 5 minutes with none, the repo has no CI
|
|
64
|
+
for this PR. Continue.
|
|
65
|
+
- Red: go to [Fix a red check](#fix-a-red-check).
|
|
66
|
+
5. Merge once green: `gh pr merge --<mergeMethod> --delete-branch`, adding `--auto` when
|
|
67
|
+
`autoMerge: true`. On a refusal for review, go to [Stop at a human gate](#stop-at-a-human-gate).
|
|
68
|
+
6. Confirm `gh pr view --json state,mergeCommit` shows `MERGED`, then
|
|
69
|
+
`git switch <branch> && git pull --ff-only`.
|
|
70
|
+
|
|
71
|
+
## Flow: merge-queue
|
|
72
|
+
|
|
73
|
+
1. Run steps 1–4 of [pull-request](#flow-pull-request).
|
|
74
|
+
2. Enqueue:
|
|
75
|
+
- `queue: mergify`: load the `mergify` skill. Enqueue as its watch contract says, then run its
|
|
76
|
+
`scripts/watch-pr-delivery.mjs` to a verdict. Enqueue several ready PRs together.
|
|
77
|
+
- `queue: github`: `gh pr merge --auto` with no merge method; the queue sets it.
|
|
78
|
+
3. Dequeued: with Mergify, follow its dequeue-reason table. Re-enqueue only after the cause is fixed.
|
|
79
|
+
4. Confirm the merge and update the local default branch as in pull-request step 6.
|
|
80
|
+
|
|
81
|
+
## Fix a red check
|
|
82
|
+
|
|
83
|
+
1. Read the failure: `gh run view <run-id> --log-failed`.
|
|
84
|
+
2. Caused by this change: fix, commit, push. In a stack repo, amend the PR's commit and push with
|
|
85
|
+
`stack-push.mjs`; a new commit opens a new PR. Stop after three rounds and report.
|
|
86
|
+
3. Not caused by this change (flake, infrastructure, unrelated code): rerun once with
|
|
87
|
+
`gh run rerun <run-id> --failed`. Still red: report it; do not edit unrelated code.
|
|
88
|
+
4. Never skip, disable, or weaken a check to turn it green.
|
|
89
|
+
5. A push to a queued PR dequeues it. Re-enqueue after the new run is green.
|
|
90
|
+
|
|
91
|
+
## Stop at a human gate
|
|
92
|
+
|
|
93
|
+
Stop and report when a merge needs what only a human gives: a required approval, a code-owner
|
|
94
|
+
review, a `CHANGES_REQUESTED` review, or a fix outside this change. Never approve your own PR,
|
|
95
|
+
merge with `--admin`, or bypass a rule. Pushing to the default branch is allowed only in the
|
|
96
|
+
`direct` flow.
|
|
97
|
+
|
|
98
|
+
## Persist to CONTRIBUTING.md
|
|
99
|
+
|
|
100
|
+
Only when the user asks, or accepts the offer in [Deliver](#deliver) step 2. From the target
|
|
101
|
+
repo's root:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
node "$SKILL_DIR/scripts/persist-conventions.mjs" --flow <direct|pull-request|merge-queue> \
|
|
105
|
+
[--done merged|committed] [--merge-method squash|merge|rebase] [--delivery-only] # preview
|
|
106
|
+
node "$SKILL_DIR/scripts/persist-conventions.mjs" --flow <flow> ... --write # write
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- Writes [references/ci-conventions.md](references/ci-conventions.md) as `## CI conventions` and the
|
|
110
|
+
flow as `## Delivery`, each between `conventions:<id>` markers; a re-run replaces only those blocks.
|
|
111
|
+
- `--done` defaults to `merged`; `--merge-method` (default `squash`) applies to `pull-request`.
|
|
112
|
+
- Pass `--delivery-only` for a repo without GitHub Actions workflows. Without `--flow`, writes CI
|
|
113
|
+
conventions only.
|
|
114
|
+
- Adds a pointer to `AGENTS.md` unless it names `CONTRIBUTING.md`; creates missing files.
|
|
115
|
+
- Creates a missing `CLAUDE.md` as a symlink to `AGENTS.md`. Adds the pointer to a regular
|
|
116
|
+
`CLAUDE.md` that names neither file. Leaves a symlinked `CLAUDE.md` alone.
|
|
117
|
+
- Report each file's result line. Committing the files is a change of its own: deliver it with this skill.
|
|
118
|
+
|
|
119
|
+
## Related skills
|
|
120
|
+
|
|
121
|
+
- `github-actions`: write and debug workflow YAML, the one required check, CI speed.
|
|
122
|
+
- `mergify`: queue config, branch rulesets, the delivery watcher, stuck or dequeued PRs.
|
|
123
|
+
- `resolve-issues` and `rush-issues` deliver their own PRs; do not run this skill inside them.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## CI conventions
|
|
2
|
+
|
|
3
|
+
1. Deploy only from Cloud Build; use workflows to verify.
|
|
4
|
+
2. Require one `gate` job (`if: always()`) per lane and nothing else.
|
|
5
|
+
3. Never put `paths:` or `paths-ignore:` on a workflow that reports a required check.
|
|
6
|
+
4. Keep PR checks under 10 minutes, run heavy suites in the merge queue, and test the deployed revision after deploy.
|
|
7
|
+
5. Keep the PR and queue lanes in one `ci.yml`; put repeated setup in a local composite action.
|
|
8
|
+
6. Set `timeout-minutes` on every job; cancel superseded runs on PRs only.
|
|
9
|
+
7. Set `permissions: contents: read`, SHA-pin third-party actions, and pass `${{ }}` through `env:`, never inline in `run:`.
|
|
10
|
+
8. Fail on a missing secret; never set `continue-on-error` on tests.
|
|
11
|
+
9. Fork-guard self-hosted jobs, set `persist-credentials: false`, and remove started containers in `if: always()`.
|
|
12
|
+
10. Alert on failed scheduled runs.
|
|
13
|
+
11. Never make an AI review the only gate or pass it on timeout.
|
|
14
|
+
12. Lint workflows with `actionlint`; don't write tests that read workflow files.
|
|
@@ -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,105 @@
|
|
|
1
|
+
// flow-core — the delivery declaration and the flow guess. Pure and import-only:
|
|
2
|
+
// flow.mjs gathers the facts (CONTRIBUTING.md, git history, GitHub settings) and
|
|
3
|
+
// persist-conventions.mjs writes the section.
|
|
4
|
+
|
|
5
|
+
export const FLOWS = ['direct', 'pull-request', 'merge-queue']
|
|
6
|
+
export const DONE = ['merged', 'committed']
|
|
7
|
+
export const MERGE_METHODS = ['squash', 'merge', 'rebase']
|
|
8
|
+
|
|
9
|
+
const PR_MERGE_SUBJECT = /^Merge pull request #\d+/
|
|
10
|
+
const SQUASH_SUBJECT = /\(#\d+\)\s*$/
|
|
11
|
+
const HISTORY_PR_SHARE = 0.5
|
|
12
|
+
const RECENT = 5
|
|
13
|
+
|
|
14
|
+
const STEPS = {
|
|
15
|
+
direct: (_method) => 'run the local checks, `git pull --rebase` onto `main`, and push to `main`. Never force-push.',
|
|
16
|
+
'pull-request': (method) => `push a branch, open a ready PR, wait for the required checks, merge with \`${method}\`, and confirm the merge.`,
|
|
17
|
+
'merge-queue': (_method) => 'push a branch, open a ready PR, wait for the checks, enqueue it with the `mergify` skill, and run its watcher to a verdict.',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function validateDelivery({ flow, done = 'merged', mergeMethod = 'squash' }) {
|
|
21
|
+
const errors = []
|
|
22
|
+
if (!FLOWS.includes(flow)) errors.push(`flow must be one of ${FLOWS.join(', ')}`)
|
|
23
|
+
if (!DONE.includes(done)) errors.push(`done must be one of ${DONE.join(', ')}`)
|
|
24
|
+
if (!MERGE_METHODS.includes(mergeMethod)) errors.push(`merge-method must be one of ${MERGE_METHODS.join(', ')}`)
|
|
25
|
+
return errors
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// The `## Delivery` section body that persist-conventions writes.
|
|
29
|
+
export function renderDelivery({ flow, done = 'merged', mergeMethod = 'squash' }) {
|
|
30
|
+
const lines = ['## Delivery', '', `- flow: ${flow}`, `- done: ${done}`]
|
|
31
|
+
if (flow === 'pull-request') lines.push(`- merge-method: ${mergeMethod}`)
|
|
32
|
+
lines.push('')
|
|
33
|
+
const steps = STEPS[flow](mergeMethod)
|
|
34
|
+
lines.push(done === 'merged'
|
|
35
|
+
? `After committing, deliver with the \`github-flow\` skill: ${steps} Do not stop at the commit.`
|
|
36
|
+
: `After committing, ask before pushing. Once approved, deliver with the \`github-flow\` skill: ${steps}`)
|
|
37
|
+
return `${lines.join('\n')}\n`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Read the declaration from CONTRIBUTING.md text: the `## Delivery` section,
|
|
41
|
+
// written by persist-conventions or by hand. Null when absent or without a valid flow.
|
|
42
|
+
export function parseDelivery(text) {
|
|
43
|
+
if (typeof text !== 'string') return null
|
|
44
|
+
const start = text.search(/^## Delivery\s*$/m)
|
|
45
|
+
if (start === -1) return null
|
|
46
|
+
const rest = text.slice(start).split('\n').slice(1)
|
|
47
|
+
const end = rest.findIndex((line) => /^#{1,2} /.test(line))
|
|
48
|
+
const body = (end === -1 ? rest : rest.slice(0, end)).join('\n')
|
|
49
|
+
const field = (name) => body.match(new RegExp(`^\\s*[-*]?\\s*${name}:\\s*([\\w-]+)`, 'm'))?.[1]
|
|
50
|
+
const flow = field('flow')
|
|
51
|
+
if (!FLOWS.includes(flow)) return null
|
|
52
|
+
const done = DONE.includes(field('done')) ? field('done') : 'committed'
|
|
53
|
+
const mergeMethod = MERGE_METHODS.includes(field('merge-method')) ? field('merge-method') : 'squash'
|
|
54
|
+
return { flow, done, mergeMethod }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Guess the flow from facts when nothing is declared. `done` is always
|
|
58
|
+
// `committed`: an undeclared repo asks before pushing.
|
|
59
|
+
//
|
|
60
|
+
// facts: {
|
|
61
|
+
// mergifyConfig: boolean, a Mergify config file in the repo
|
|
62
|
+
// ruleTypes: string[] | null, rule types on the default branch; null = unreadable
|
|
63
|
+
// autoMerge: boolean | null, repo allows auto-merge; null = unreadable
|
|
64
|
+
// allowedMethods: string[] | null, merge methods the repo allows; null = unreadable
|
|
65
|
+
// subjects: string[], first-parent commit subjects on the default branch, newest first
|
|
66
|
+
// }
|
|
67
|
+
export function guessFlow(facts) {
|
|
68
|
+
const ruleTypes = facts.ruleTypes ?? []
|
|
69
|
+
const subjects = facts.subjects ?? []
|
|
70
|
+
const evidence = []
|
|
71
|
+
const merges = subjects.filter((s) => PR_MERGE_SUBJECT.test(s)).length
|
|
72
|
+
const squashes = subjects.filter((s) => SQUASH_SUBJECT.test(s)).length
|
|
73
|
+
const fromPr = (s) => PR_MERGE_SUBJECT.test(s) || SQUASH_SUBJECT.test(s)
|
|
74
|
+
const recent = subjects.slice(0, RECENT)
|
|
75
|
+
const recentShare = recent.length ? recent.filter(fromPr).length / recent.length : 0
|
|
76
|
+
if (facts.ruleTypes == null) evidence.push('GitHub branch rules unreadable')
|
|
77
|
+
else evidence.push(`branch rules: ${ruleTypes.length ? ruleTypes.join(', ') : 'none'}`)
|
|
78
|
+
evidence.push(`${merges + squashes} of the last ${subjects.length} commits on the default branch came from PRs, ${recent.filter(fromPr).length} of the last ${recent.length}`)
|
|
79
|
+
|
|
80
|
+
let flow
|
|
81
|
+
let queue = null
|
|
82
|
+
if (facts.mergifyConfig) {
|
|
83
|
+
flow = 'merge-queue'
|
|
84
|
+
queue = 'mergify'
|
|
85
|
+
evidence.push('Mergify config present')
|
|
86
|
+
} else if (ruleTypes.includes('merge_queue')) {
|
|
87
|
+
flow = 'merge-queue'
|
|
88
|
+
queue = 'github'
|
|
89
|
+
evidence.push('GitHub merge queue rule present')
|
|
90
|
+
} else if (ruleTypes.includes('required_status_checks')) {
|
|
91
|
+
flow = 'pull-request'
|
|
92
|
+
evidence.push('required status checks on the default branch')
|
|
93
|
+
} else {
|
|
94
|
+
flow = recentShare >= HISTORY_PR_SHARE ? 'pull-request' : 'direct'
|
|
95
|
+
if (flow === 'direct' && ruleTypes.includes('pull_request')) {
|
|
96
|
+
evidence.push('a PR rule exists, but history shows direct pushes (bypass)')
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const allowed = (facts.allowedMethods ?? MERGE_METHODS).filter((m) => MERGE_METHODS.includes(m))
|
|
101
|
+
const fromHistory = merges > squashes ? 'merge' : squashes > 0 ? 'squash' : null
|
|
102
|
+
const mergeMethod = fromHistory && allowed.includes(fromHistory) ? fromHistory : (allowed[0] ?? 'squash')
|
|
103
|
+
|
|
104
|
+
return { source: 'detected', flow, done: 'committed', mergeMethod, queue, autoMerge: facts.autoMerge ?? null, evidence }
|
|
105
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// flow — print the repo's delivery flow as JSON: the declaration from
|
|
2
|
+
// CONTRIBUTING.md (`source: declared`), or a guess from GitHub settings and
|
|
3
|
+
// history (`source: detected`). Read-only.
|
|
4
|
+
//
|
|
5
|
+
// node flow.mjs [--repo-root <dir>]
|
|
6
|
+
//
|
|
7
|
+
// Exit 0 with the JSON; 2 on a usage error or when the directory is not a git repo.
|
|
8
|
+
import { execFileSync } from 'node:child_process'
|
|
9
|
+
import fs from 'node:fs'
|
|
10
|
+
import path from 'node:path'
|
|
11
|
+
import { guessFlow, parseDelivery } from './flow-core.mjs'
|
|
12
|
+
|
|
13
|
+
const MERGIFY_FILES = ['.mergify.yml', '.mergify/config.yml', '.github/mergify.yml']
|
|
14
|
+
const HISTORY_DEPTH = 20
|
|
15
|
+
|
|
16
|
+
function sh(cmd, args, cwd) {
|
|
17
|
+
try {
|
|
18
|
+
return execFileSync(cmd, args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
|
|
19
|
+
} catch {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function ghJson(args, cwd) {
|
|
25
|
+
const out = sh('gh', args, cwd)
|
|
26
|
+
if (out == null) return null
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(out)
|
|
29
|
+
} catch {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const argv = process.argv.slice(2)
|
|
35
|
+
let root = process.cwd()
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
if (argv[i] === '--repo-root' && argv[i + 1]) root = path.resolve(argv[++i])
|
|
38
|
+
else {
|
|
39
|
+
console.error(`flow: unknown argument ${argv[i]}`)
|
|
40
|
+
process.exit(2)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const top = sh('git', ['rev-parse', '--show-toplevel'], root)
|
|
44
|
+
if (!top) {
|
|
45
|
+
console.error(`flow: not a git repository: ${root}`)
|
|
46
|
+
process.exit(2)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const contributing = path.join(top, 'CONTRIBUTING.md')
|
|
50
|
+
const mergifyConfig = MERGIFY_FILES.some((f) => fs.existsSync(path.join(top, f)))
|
|
51
|
+
const localBranch = sh('git', ['symbolic-ref', '--short', 'refs/remotes/origin/HEAD'], top)?.replace(/^origin\//, '') ?? null
|
|
52
|
+
const declared = parseDelivery(fs.existsSync(contributing) ? fs.readFileSync(contributing, 'utf8') : null)
|
|
53
|
+
|
|
54
|
+
const github = declared?.flow === 'direct' ? null : ghJson(['repo', 'view', '--json', 'nameWithOwner,defaultBranchRef'], top)
|
|
55
|
+
const repo = github?.nameWithOwner ?? null
|
|
56
|
+
const branch = github?.defaultBranchRef?.name ?? localBranch ?? 'main'
|
|
57
|
+
const settings = repo ? ghJson(['api', `repos/${repo}`], top) : null
|
|
58
|
+
const autoMerge = settings ? Boolean(settings.allow_auto_merge) : null
|
|
59
|
+
|
|
60
|
+
if (declared) {
|
|
61
|
+
const queue = declared.flow === 'merge-queue' ? (mergifyConfig ? 'mergify' : 'github') : null
|
|
62
|
+
console.log(JSON.stringify({ repo, branch, source: 'declared', ...declared, queue, autoMerge }, null, 2))
|
|
63
|
+
process.exit(0)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const rules = repo ? ghJson(['api', `repos/${repo}/rules/branches/${branch}`], top) : null
|
|
67
|
+
const log = sh('git', ['log', '--first-parent', `-${HISTORY_DEPTH}`, '--format=%s', `origin/${branch}`], top)
|
|
68
|
+
?? sh('git', ['log', '--first-parent', `-${HISTORY_DEPTH}`, '--format=%s', branch], top)
|
|
69
|
+
|
|
70
|
+
const allowedMethods = settings
|
|
71
|
+
? [settings.allow_squash_merge && 'squash', settings.allow_merge_commit && 'merge', settings.allow_rebase_merge && 'rebase'].filter(Boolean)
|
|
72
|
+
: null
|
|
73
|
+
|
|
74
|
+
const guess = guessFlow({
|
|
75
|
+
mergifyConfig,
|
|
76
|
+
ruleTypes: Array.isArray(rules) ? [...new Set(rules.map((r) => r.type))] : null,
|
|
77
|
+
autoMerge,
|
|
78
|
+
allowedMethods,
|
|
79
|
+
subjects: log ? log.split('\n').filter(Boolean) : [],
|
|
80
|
+
})
|
|
81
|
+
console.log(JSON.stringify({ repo, branch, ...guess }, null, 2))
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Tests for the delivery declaration and the flow guess. The guess fixtures are
|
|
2
|
+
// the facts read from four real repos on 2026-10-04, each with the flow its owner
|
|
3
|
+
// says it uses.
|
|
4
|
+
import { test } from 'node:test'
|
|
5
|
+
import assert from 'node:assert/strict'
|
|
6
|
+
import { spawnSync } from 'node:child_process'
|
|
7
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
8
|
+
import { tmpdir } from 'node:os'
|
|
9
|
+
import { join } from 'node:path'
|
|
10
|
+
import { fileURLToPath } from 'node:url'
|
|
11
|
+
|
|
12
|
+
import { guessFlow, parseDelivery, renderDelivery, validateDelivery } from './flow-core.mjs'
|
|
13
|
+
|
|
14
|
+
const CLI = fileURLToPath(new URL('./flow.mjs', import.meta.url))
|
|
15
|
+
const direct = (n) => Array.from({ length: n }, (_, i) => `docs: note ${i}`)
|
|
16
|
+
const merged = (n) => Array.from({ length: n }, (_, i) => `Merge pull request #${100 + i} from 1aboveio/topic-${i}`)
|
|
17
|
+
const squashed = (n) => Array.from({ length: n }, (_, i) => `fix: thing ${i} (#${200 + i})`)
|
|
18
|
+
|
|
19
|
+
test('proxy-cache: a PR rule everyone bypasses, direct history -> direct', () => {
|
|
20
|
+
const guess = guessFlow({ mergifyConfig: false, ruleTypes: ['pull_request'], autoMerge: false, allowedMethods: ['squash', 'merge', 'rebase'], subjects: direct(20) })
|
|
21
|
+
assert.equal(guess.flow, 'direct')
|
|
22
|
+
assert.equal(guess.done, 'committed')
|
|
23
|
+
assert.ok(guess.evidence.some((e) => /bypass/.test(e)))
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('github-runner: recent PR merges after older direct pushes -> pull-request with merge commits', () => {
|
|
27
|
+
const subjects = [...merged(5), ...direct(13), ...merged(2)]
|
|
28
|
+
const guess = guessFlow({ mergifyConfig: false, ruleTypes: ['pull_request'], autoMerge: false, allowedMethods: ['squash', 'merge', 'rebase'], subjects })
|
|
29
|
+
assert.equal(guess.flow, 'pull-request')
|
|
30
|
+
assert.equal(guess.mergeMethod, 'merge')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('pi-better-harness: required checks and auto-merge -> pull-request, squash, auto-merge', () => {
|
|
34
|
+
const guess = guessFlow({ mergifyConfig: false, ruleTypes: ['pull_request', 'deletion', 'non_fast_forward', 'required_status_checks'], autoMerge: true, allowedMethods: ['squash', 'merge', 'rebase'], subjects: squashed(20) })
|
|
35
|
+
assert.deepEqual([guess.flow, guess.mergeMethod, guess.autoMerge, guess.queue], ['pull-request', 'squash', true, null])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('ai: a Mergify config -> merge-queue through mergify', () => {
|
|
39
|
+
const guess = guessFlow({ mergifyConfig: true, ruleTypes: ['pull_request', 'required_status_checks', 'update'], autoMerge: true, allowedMethods: ['squash', 'merge'], subjects: merged(20) })
|
|
40
|
+
assert.deepEqual([guess.flow, guess.queue], ['merge-queue', 'mergify'])
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('a GitHub merge_queue rule -> merge-queue through github', () => {
|
|
44
|
+
const guess = guessFlow({ mergifyConfig: false, ruleTypes: ['merge_queue', 'pull_request'], autoMerge: true, allowedMethods: ['squash'], subjects: squashed(3) })
|
|
45
|
+
assert.deepEqual([guess.flow, guess.queue], ['merge-queue', 'github'])
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('unreadable GitHub settings still guess from history and say so', () => {
|
|
49
|
+
const guess = guessFlow({ mergifyConfig: false, ruleTypes: null, autoMerge: null, allowedMethods: null, subjects: direct(4) })
|
|
50
|
+
assert.equal(guess.flow, 'direct')
|
|
51
|
+
assert.ok(guess.evidence.includes('GitHub branch rules unreadable'))
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('the history merge method is used only when the repo allows it', () => {
|
|
55
|
+
const guess = guessFlow({ mergifyConfig: false, ruleTypes: ['required_status_checks'], autoMerge: false, allowedMethods: ['rebase'], subjects: merged(5) })
|
|
56
|
+
assert.equal(guess.mergeMethod, 'rebase')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('every rendered declaration parses back to the same values', () => {
|
|
60
|
+
for (const flow of ['direct', 'pull-request', 'merge-queue']) {
|
|
61
|
+
for (const done of ['merged', 'committed']) {
|
|
62
|
+
for (const mergeMethod of ['squash', 'merge', 'rebase']) {
|
|
63
|
+
const text = `# Contributing\n\n${renderDelivery({ flow, done, mergeMethod })}\n## Next\n- flow: direct\n`
|
|
64
|
+
const parsed = parseDelivery(text)
|
|
65
|
+
assert.deepEqual(parsed, { flow, done, mergeMethod: flow === 'pull-request' ? mergeMethod : 'squash' })
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('the rendered section tells the agent not to stop at the commit only when done is merged', () => {
|
|
72
|
+
assert.match(renderDelivery({ flow: 'direct', done: 'merged' }), /Do not stop at the commit/)
|
|
73
|
+
assert.match(renderDelivery({ flow: 'direct', done: 'committed' }), /ask before pushing/)
|
|
74
|
+
assert.doesNotMatch(renderDelivery({ flow: 'direct', done: 'committed' }), /Do not stop/)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('a hand-written section is read; a missing or unknown flow is not a declaration', () => {
|
|
78
|
+
assert.deepEqual(parseDelivery('## Delivery\n\nflow: merge-queue\ndone: merged\n'), { flow: 'merge-queue', done: 'merged', mergeMethod: 'squash' })
|
|
79
|
+
assert.equal(parseDelivery('## Delivery\n\n- done: merged\n'), null)
|
|
80
|
+
assert.equal(parseDelivery('## Delivery\n\n- flow: trunk\n'), null)
|
|
81
|
+
assert.equal(parseDelivery('## Other\n\n- flow: direct\n'), null)
|
|
82
|
+
assert.equal(parseDelivery(null), null)
|
|
83
|
+
assert.equal(parseDelivery('## Delivery\n\n- flow: direct\n').done, 'committed')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test('validateDelivery rejects unknown values', () => {
|
|
87
|
+
assert.deepEqual(validateDelivery({ flow: 'direct' }), [])
|
|
88
|
+
assert.equal(validateDelivery({ flow: 'gitflow', done: 'shipped', mergeMethod: 'ff' }).length, 3)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('the CLI prints the declared flow without calling GitHub', () => {
|
|
92
|
+
const dir = mkdtempSync(join(tmpdir(), 'github-flow-'))
|
|
93
|
+
try {
|
|
94
|
+
spawnSync('git', ['init', '-q', dir])
|
|
95
|
+
writeFileSync(join(dir, 'CONTRIBUTING.md'), `# Contributing\n\n${renderDelivery({ flow: 'pull-request', mergeMethod: 'merge' })}`)
|
|
96
|
+
writeFileSync(join(dir, '.mergify.yml'), 'queue_rules: []\n')
|
|
97
|
+
const res = spawnSync(process.execPath, [CLI, '--repo-root', dir], { encoding: 'utf8', env: { ...process.env, PATH: '/usr/bin:/bin' } })
|
|
98
|
+
assert.equal(res.status, 0, res.stderr)
|
|
99
|
+
const out = JSON.parse(res.stdout)
|
|
100
|
+
assert.deepEqual([out.source, out.flow, out.done, out.mergeMethod, out.queue], ['declared', 'pull-request', 'merged', 'merge', null])
|
|
101
|
+
} finally {
|
|
102
|
+
rmSync(dir, { recursive: true, force: true })
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('the CLI fails with exit 2 outside a git repo and on an unknown argument', () => {
|
|
107
|
+
const dir = mkdtempSync(join(tmpdir(), 'github-flow-'))
|
|
108
|
+
try {
|
|
109
|
+
assert.equal(spawnSync(process.execPath, [CLI, '--repo-root', dir], { encoding: 'utf8', env: { ...process.env, GIT_CEILING_DIRECTORIES: tmpdir() } }).status, 2)
|
|
110
|
+
assert.equal(spawnSync(process.execPath, [CLI, '--wat'], { encoding: 'utf8' }).status, 2)
|
|
111
|
+
} finally {
|
|
112
|
+
rmSync(dir, { recursive: true, force: true })
|
|
113
|
+
}
|
|
114
|
+
})
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// persist-conventions-core — write one skill's section into a repo's
|
|
2
|
+
// CONTRIBUTING.md, point AGENTS.md at the file, and make CLAUDE.md a symlink to
|
|
3
|
+
// AGENTS.md (Claude Code reads CLAUDE.md, not AGENTS.md). Import-only: each skill's
|
|
4
|
+
// `persist-conventions.mjs` is the always-running CLI wrapper that names its
|
|
5
|
+
// section, so no main-module guard here.
|
|
6
|
+
//
|
|
7
|
+
// Byte-identical copies live in test-quality (Testing conventions), github-flow
|
|
8
|
+
// (CI conventions, Delivery) and data-catalog (Data catalog conventions);
|
|
9
|
+
// skills/conventions-sections.test.mjs keeps them identical and proves the sections
|
|
10
|
+
// coexist in one file.
|
|
11
|
+
//
|
|
12
|
+
// A section sits between `conventions:<id>` markers, so a re-run replaces only
|
|
13
|
+
// that block and keeps everything else, including other skills' sections.
|
|
14
|
+
// Nothing is written without --write: the user triggers the write, not an agent.
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs'
|
|
17
|
+
import path from 'node:path'
|
|
18
|
+
|
|
19
|
+
export const CONTRIBUTING_FILE = 'CONTRIBUTING.md'
|
|
20
|
+
const MENTIONS_CONTRIBUTING = /(?:^|[^\w-])CONTRIBUTING\.md/
|
|
21
|
+
|
|
22
|
+
export const AGENTS_SECTION = [
|
|
23
|
+
'## Contributing',
|
|
24
|
+
'',
|
|
25
|
+
`Follow [${CONTRIBUTING_FILE}](${CONTRIBUTING_FILE}) when writing, reviewing, or delivering code: tests, CI, data definitions, and what to do after each commit.`,
|
|
26
|
+
'',
|
|
27
|
+
].join('\n')
|
|
28
|
+
|
|
29
|
+
export function markers(id) {
|
|
30
|
+
return [`<!-- conventions:${id}:start -->`, `<!-- conventions:${id}:end -->`]
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function sectionBlock({ id, owner, body }) {
|
|
34
|
+
const [start, end] = markers(id)
|
|
35
|
+
const note = `<!-- Written by the ${owner} skill: re-run its persist-conventions.mjs --write to update; edit outside these markers. -->`
|
|
36
|
+
return `${start}\n${note}\n\n${body.trim()}\n${end}\n`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Pure: the new CONTRIBUTING.md text given the current one (or null).
|
|
40
|
+
export function renderConventions(current, id, block) {
|
|
41
|
+
if (current == null) return `# Contributing\n\n${block}`
|
|
42
|
+
const [start, end] = markers(id)
|
|
43
|
+
const from = current.indexOf(start)
|
|
44
|
+
const to = current.indexOf(end)
|
|
45
|
+
if (from !== -1 && to > from) {
|
|
46
|
+
const after = current.slice(to + end.length).replace(/^\r?\n/, '')
|
|
47
|
+
return current.slice(0, from) + block + after
|
|
48
|
+
}
|
|
49
|
+
return `${current.replace(/\s*$/, '')}\n\n${block}`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Pure: the new AGENTS.md text given the current one (or null).
|
|
53
|
+
export function renderAgents(current) {
|
|
54
|
+
if (current == null) return `# AGENTS.md\n\n${AGENTS_SECTION}`
|
|
55
|
+
if (MENTIONS_CONTRIBUTING.test(current)) return current
|
|
56
|
+
return `${current.replace(/\s*$/, '')}\n\n${AGENTS_SECTION}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// A missing CLAUDE.md becomes a symlink to AGENTS.md.
|
|
60
|
+
export const LINK_TO_AGENTS = Symbol('link CLAUDE.md to AGENTS.md')
|
|
61
|
+
|
|
62
|
+
// Pure: the new CLAUDE.md text given the current one (or null). A missing file
|
|
63
|
+
// becomes LINK_TO_AGENTS; a regular file keeps its content and gains the pointer
|
|
64
|
+
// unless it already names AGENTS.md or CONTRIBUTING.md.
|
|
65
|
+
export function renderClaude(current) {
|
|
66
|
+
if (current == null) return LINK_TO_AGENTS
|
|
67
|
+
if (/(?:^|[^\w-])(?:AGENTS|CONTRIBUTING)\.md/.test(current)) return current
|
|
68
|
+
return `${current.replace(/\s*$/, '')}\n\n${AGENTS_SECTION}`
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function persist(repoRoot, section, { write = false } = {}) {
|
|
72
|
+
const block = sectionBlock(section)
|
|
73
|
+
const plan = [
|
|
74
|
+
[CONTRIBUTING_FILE, (text) => renderConventions(text, section.id, block)],
|
|
75
|
+
['AGENTS.md', renderAgents],
|
|
76
|
+
['CLAUDE.md', renderClaude],
|
|
77
|
+
]
|
|
78
|
+
return plan.map(([name, render]) => {
|
|
79
|
+
const file = path.join(repoRoot, name)
|
|
80
|
+
if (fs.lstatSync(file, { throwIfNoEntry: false })?.isSymbolicLink()) return { file: name, action: 'unchanged' }
|
|
81
|
+
const current = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : null
|
|
82
|
+
const next = render(current)
|
|
83
|
+
const action = current == null ? 'create' : next === current ? 'unchanged' : 'update'
|
|
84
|
+
if (next === LINK_TO_AGENTS) {
|
|
85
|
+
if (write) fs.symlinkSync('AGENTS.md', file)
|
|
86
|
+
return { file: name, action: 'link' }
|
|
87
|
+
}
|
|
88
|
+
if (write && action !== 'unchanged') fs.writeFileSync(file, next)
|
|
89
|
+
return { file: name, action }
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// `section` = { id, owner, title, body }. Exit 0 on success, 2 on a usage error.
|
|
94
|
+
export function runCli(argv, section, { cwd = process.cwd(), log = console.log } = {}) {
|
|
95
|
+
let repoRoot = cwd
|
|
96
|
+
let write = false
|
|
97
|
+
for (let i = 0; i < argv.length; i++) {
|
|
98
|
+
if (argv[i] === '--write') write = true
|
|
99
|
+
else if (argv[i] === '--repo-root' && argv[i + 1]) repoRoot = path.resolve(cwd, argv[++i])
|
|
100
|
+
else {
|
|
101
|
+
log(`persist-conventions: unknown argument ${argv[i]}`)
|
|
102
|
+
return 2
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (!fs.statSync(repoRoot, { throwIfNoEntry: false })?.isDirectory()) {
|
|
106
|
+
log(`persist-conventions: not a directory: ${repoRoot}`)
|
|
107
|
+
return 2
|
|
108
|
+
}
|
|
109
|
+
const results = persist(repoRoot, section, { write })
|
|
110
|
+
const done = { create: 'created', link: 'linked to AGENTS.md', update: 'updated', unchanged: 'unchanged' }
|
|
111
|
+
for (const r of results) log(` ${r.file}: ${write || r.action === 'unchanged' ? done[r.action] : `would ${r.action}`}`)
|
|
112
|
+
const changed = results.filter((r) => r.action !== 'unchanged').length
|
|
113
|
+
log(write
|
|
114
|
+
? `persist-conventions: ${section.title}: ${changed} file(s) written, ${results.length - changed} unchanged`
|
|
115
|
+
: `persist-conventions: ${section.title}: preview only, ${changed} file(s) would change; re-run with --write to write`)
|
|
116
|
+
return 0
|
|
117
|
+
}
|