@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,398 @@
|
|
|
1
|
+
// head-check-set — the FULL observed state of one commit, not the named subset of it.
|
|
2
|
+
//
|
|
3
|
+
// A required-check plan answers "are the checks I named green?". #1081 is what that
|
|
4
|
+
// question cannot see. Two release workflows were rejected by GitHub at validation
|
|
5
|
+
// time; every push produced two runs that completed in the same second having executed
|
|
6
|
+
// ZERO jobs, named after the file path instead of the declared `name:`. That was
|
|
7
|
+
// visible for seven hours across fourteen commits, and the unit still earned an
|
|
8
|
+
// independent PASS and a merge-ready mark, because the one check anybody read
|
|
9
|
+
// (`skill-script-tests`) was green — and it genuinely was.
|
|
10
|
+
//
|
|
11
|
+
// THE SUBTLETY THAT DEFEATS THE OBVIOUS FIX. "Read every check-run instead of the
|
|
12
|
+
// named ones" would ALSO have missed #1081. A workflow GitHub cannot parse produces no
|
|
13
|
+
// check-run at all — not a red one, none. The real observation at that SHA:
|
|
14
|
+
//
|
|
15
|
+
// GET /commits/ee5dd91a…/check-runs → 4 entries, every one success/neutral/skipped
|
|
16
|
+
// GET /commits/ee5dd91a…/status → state "pending", zero statuses
|
|
17
|
+
// GET /actions/runs?head_sha=ee5dd91a… → 3 runs, TWO of them conclusion "failure"
|
|
18
|
+
// with name == path and zero jobs
|
|
19
|
+
//
|
|
20
|
+
// So the full state of a commit is the union of three channels — check-runs, legacy
|
|
21
|
+
// commit statuses, and Actions runs — and the third is the only one where a startup
|
|
22
|
+
// failure lives. This module classifies that union. Both halves are load-bearing: the
|
|
23
|
+
// union is what makes undeclared red visible, and the zero-job run is what makes the
|
|
24
|
+
// #1081 class NAMEABLE rather than a number in a count.
|
|
25
|
+
//
|
|
26
|
+
// WHAT THIS DELIBERATELY DOES NOT DO. It does not gate. Whether a red check nobody
|
|
27
|
+
// declared required should block a merge is a policy decision belonging to the human
|
|
28
|
+
// and to `.mergify.yml`, and a reporting script that quietly changed what merges would
|
|
29
|
+
// be a worse defect than the one it fixes. The partition names `undeclaredRed`
|
|
30
|
+
// separately from `requiredRed` precisely so a caller can act on the difference; the
|
|
31
|
+
// only outcome this module calls failing is the one the existing contract already
|
|
32
|
+
// blocks on — a REQUIRED check red or absent.
|
|
33
|
+
|
|
34
|
+
export const HEAD_CHECK_SET_VERSION = 1
|
|
35
|
+
export const HEAD_CHECK_SET_KIND = 'head-check-set'
|
|
36
|
+
export const OBSERVATION_SOURCES = Object.freeze(['check-run', 'commit-status', 'actions-run'])
|
|
37
|
+
export const OBSERVATION_STATES = Object.freeze(['green', 'red', 'neutral', 'pending'])
|
|
38
|
+
|
|
39
|
+
// Why `cancelled` counts as red: a cancelled required check is not a passed one, and
|
|
40
|
+
// the surrounding contract has said "skipped is never success" since epic-892. Neutral
|
|
41
|
+
// and skipped stay `neutral` — they are not passes either, but they are not evidence of
|
|
42
|
+
// breakage, and conflating the two is how a report gets ignored.
|
|
43
|
+
const RED_CONCLUSIONS = new Set(['failure', 'timed_out', 'action_required', 'startup_failure', 'stale', 'cancelled'])
|
|
44
|
+
const NEUTRAL_CONCLUSIONS = new Set(['skipped', 'neutral'])
|
|
45
|
+
const COMPLETED = new Set(['completed'])
|
|
46
|
+
|
|
47
|
+
// A run GitHub could not parse is reported with its file path where its name belongs,
|
|
48
|
+
// because there is no parsed `name:` to report. Corroborating, never sufficient: a
|
|
49
|
+
// workflow may legitimately declare no `name:`, in which case GitHub also uses the path.
|
|
50
|
+
const WORKFLOW_PATH = /^\.github\/workflows\/[^/]+\.ya?ml$/
|
|
51
|
+
|
|
52
|
+
const isObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
53
|
+
const nonEmpty = (value) => typeof value === 'string' && value.trim().length > 0
|
|
54
|
+
const SHA = /^[0-9a-f]{40}$/i
|
|
55
|
+
const lower = (value) => (value == null ? null : String(value).toLowerCase())
|
|
56
|
+
|
|
57
|
+
function stateOf(status, conclusion) {
|
|
58
|
+
const normalizedStatus = lower(status)
|
|
59
|
+
const normalizedConclusion = lower(conclusion)
|
|
60
|
+
if (normalizedStatus !== null && !COMPLETED.has(normalizedStatus)) return 'pending'
|
|
61
|
+
if (normalizedConclusion === null) return 'pending'
|
|
62
|
+
if (normalizedConclusion === 'success') return 'green'
|
|
63
|
+
if (NEUTRAL_CONCLUSIONS.has(normalizedConclusion)) return 'neutral'
|
|
64
|
+
if (RED_CONCLUSIONS.has(normalizedConclusion)) return 'red'
|
|
65
|
+
// Deny-by-default on a conclusion this module has never seen: an unknown conclusion
|
|
66
|
+
// read as green is exactly the failure this file exists to remove.
|
|
67
|
+
return 'red'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function commitStatusState(state) {
|
|
71
|
+
const normalized = lower(state)
|
|
72
|
+
if (normalized === 'success') return 'green'
|
|
73
|
+
if (normalized === 'pending') return 'pending'
|
|
74
|
+
return 'red'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Every check name the plan declares required, in any phase. */
|
|
78
|
+
export function requiredCheckNames(plan) {
|
|
79
|
+
const fromChecks = (plan?.checks || [])
|
|
80
|
+
.filter((check) => check?.admission === 'required' && nonEmpty(check?.name))
|
|
81
|
+
.map((check) => check.name)
|
|
82
|
+
const fromDiscovery = (plan?.discovery?.requiredChecks || []).filter(nonEmpty)
|
|
83
|
+
return [...new Set([...fromChecks, ...fromDiscovery])].sort()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function checkRunObservation(run) {
|
|
87
|
+
return {
|
|
88
|
+
source: 'check-run',
|
|
89
|
+
name: String(run?.name ?? ''),
|
|
90
|
+
state: stateOf(run?.status, run?.conclusion),
|
|
91
|
+
status: run?.status ?? null,
|
|
92
|
+
conclusion: run?.conclusion ?? null,
|
|
93
|
+
app: run?.app?.slug ?? null,
|
|
94
|
+
checkSuiteId: run?.check_suite?.id ?? null,
|
|
95
|
+
url: run?.html_url ?? null,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function commitStatusObservation(status) {
|
|
100
|
+
return {
|
|
101
|
+
source: 'commit-status',
|
|
102
|
+
name: String(status?.context ?? ''),
|
|
103
|
+
state: commitStatusState(status?.state),
|
|
104
|
+
status: 'completed',
|
|
105
|
+
conclusion: status?.state ?? null,
|
|
106
|
+
app: status?.creator?.login ?? null,
|
|
107
|
+
checkSuiteId: null,
|
|
108
|
+
url: status?.target_url ?? null,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* An Actions run, plus the two facts that make #1081 nameable.
|
|
114
|
+
*
|
|
115
|
+
* `jobCount` is supplied by the caller because it costs one extra API call per run and
|
|
116
|
+
* this module is pure. A run that has completed with `jobCount === 0` executed nothing:
|
|
117
|
+
* that is the startup-failure signature, and it is the whole reason the Actions channel
|
|
118
|
+
* is read at all. `null` means the caller could not determine it — reported as unknown,
|
|
119
|
+
* never as zero, because "we did not look" and "there were none" must not render alike.
|
|
120
|
+
*/
|
|
121
|
+
function actionsRunObservation(run) {
|
|
122
|
+
const name = String(run?.name ?? '')
|
|
123
|
+
const path = run?.path ?? null
|
|
124
|
+
const jobCount = Number.isInteger(run?.jobCount) ? run.jobCount : null
|
|
125
|
+
const state = stateOf(run?.status, run?.conclusion)
|
|
126
|
+
const completed = COMPLETED.has(lower(run?.status) ?? '')
|
|
127
|
+
return {
|
|
128
|
+
source: 'actions-run',
|
|
129
|
+
name,
|
|
130
|
+
state,
|
|
131
|
+
status: run?.status ?? null,
|
|
132
|
+
conclusion: run?.conclusion ?? null,
|
|
133
|
+
app: 'github-actions',
|
|
134
|
+
checkSuiteId: run?.check_suite_id ?? null,
|
|
135
|
+
url: run?.html_url ?? null,
|
|
136
|
+
runId: run?.id ?? null,
|
|
137
|
+
path,
|
|
138
|
+
event: run?.event ?? null,
|
|
139
|
+
jobCount,
|
|
140
|
+
// Recorded, never classified on. The obvious reading of "is this run attached to the
|
|
141
|
+
// pull request?" is the API's `pull_requests` array, and it is not usable: at
|
|
142
|
+
// ee5dd91a the perfectly healthy `pull_request`-event `Skill gates` run also carries
|
|
143
|
+
// `pull_requests: []`. Deriving an attachment boolean from it would report every
|
|
144
|
+
// healthy run as unattached. `event` is what actually distinguishes an out-of-band
|
|
145
|
+
// dispatch, and it is what `absenceReason` uses.
|
|
146
|
+
pullRequests: Array.isArray(run?.pull_requests) ? run.pull_requests.map((entry) => entry?.number ?? null) : [],
|
|
147
|
+
nameEqualsPath: nonEmpty(path) && name === path,
|
|
148
|
+
looksLikeWorkflowPath: WORKFLOW_PATH.test(name),
|
|
149
|
+
zeroJobs: completed && jobCount === 0,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Raw Actions runs (each optionally carrying an integer `jobCount`) as observations. */
|
|
154
|
+
export function observeActionsRuns(runs) {
|
|
155
|
+
return (Array.isArray(runs) ? runs : []).map(actionsRunObservation)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The #1081 signature: a run that COMPLETED, executed zero jobs, and did not succeed.
|
|
160
|
+
*
|
|
161
|
+
* Kept distinct from "a red run" on purpose. A red run with jobs failed while doing its
|
|
162
|
+
* work and its jobs say why; a red run with no jobs never started, and nothing else in
|
|
163
|
+
* the system says so — no check-run exists to be red. The name-equals-path corroboration
|
|
164
|
+
* is reported alongside rather than required, because a workflow with no declared `name:`
|
|
165
|
+
* produces the same coincidence honestly.
|
|
166
|
+
*/
|
|
167
|
+
export function startupFailures(observations) {
|
|
168
|
+
return observations
|
|
169
|
+
.filter((entry) => entry.source === 'actions-run' && entry.zeroJobs && entry.state !== 'green')
|
|
170
|
+
.map((entry) => ({
|
|
171
|
+
runId: entry.runId,
|
|
172
|
+
name: entry.name,
|
|
173
|
+
path: entry.path,
|
|
174
|
+
event: entry.event,
|
|
175
|
+
conclusion: entry.conclusion,
|
|
176
|
+
state: entry.state,
|
|
177
|
+
nameEqualsPath: entry.nameEqualsPath,
|
|
178
|
+
looksLikeWorkflowPath: entry.looksLikeWorkflowPath,
|
|
179
|
+
url: entry.url,
|
|
180
|
+
}))
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Why a required check produced no observation at all. This is #1058's distinction and
|
|
185
|
+
* it falls out of the same union: the three answers call for opposite responses, and the
|
|
186
|
+
* single string they share today ("no workflow run found") reads as *still queued* for
|
|
187
|
+
* all three.
|
|
188
|
+
*/
|
|
189
|
+
export function ciAbsence(observations) {
|
|
190
|
+
const actionsRuns = (observations || []).filter((entry) => entry.source === 'actions-run')
|
|
191
|
+
return absenceReason(observations || [], actionsRuns)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function absenceReason(observations, actionsRuns) {
|
|
195
|
+
if (observations.some((entry) => entry.state === 'pending')) {
|
|
196
|
+
return {
|
|
197
|
+
reason: 'pending',
|
|
198
|
+
detail: 'a run for this SHA has not finished; waiting is correct and dispatching another would waste a run',
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (observations.length === 0) {
|
|
202
|
+
return {
|
|
203
|
+
reason: 'no-run-anywhere',
|
|
204
|
+
detail: 'no check-run, commit status or Actions run exists for this SHA — the triggering event was most likely never delivered; waiting is futile, a workflow_dispatch or a close/reopen at the same head is the intervention',
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// #1058's third state: a run exists at this SHA, but it got there by hand. The check
|
|
208
|
+
// it produced is honest exact-head evidence and satisfies no merge-queue condition,
|
|
209
|
+
// and the situation is actionable NOW rather than something to wait out.
|
|
210
|
+
const dispatched = actionsRuns.filter((entry) => entry.event === 'workflow_dispatch')
|
|
211
|
+
if (dispatched.length && dispatched.length === actionsRuns.length) {
|
|
212
|
+
return {
|
|
213
|
+
reason: 'dispatched-out-of-band',
|
|
214
|
+
detail: `every Actions run at this SHA was started by workflow_dispatch (${dispatched.map((entry) => entry.runId).join(', ')}) — the event that would have created this check was never delivered; the dispatched run is honest exact-head evidence but satisfies no merge-queue check condition, so delivery still needs the event`,
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
reason: 'absent-though-runs-completed',
|
|
219
|
+
detail: 'runs for this SHA have completed without ever producing this check — inspect the workflow trigger and path filters, and the startupFailures channel: a workflow GitHub refuses to parse creates a run and produces no check-run at all',
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Classify the full observed state of one head SHA.
|
|
225
|
+
*
|
|
226
|
+
* @param {object} input
|
|
227
|
+
* @param {string} input.repository owner/name
|
|
228
|
+
* @param {string} input.headSha the 40-character commit being described
|
|
229
|
+
* @param {object[]} [input.checkRuns] raw `GET /commits/{sha}/check-runs` entries
|
|
230
|
+
* @param {object[]} [input.statuses] raw `GET /commits/{sha}/status` `.statuses` entries
|
|
231
|
+
* @param {object[]} [input.actionsRuns] raw `GET /actions/runs?head_sha=` entries, each
|
|
232
|
+
* optionally carrying an integer `jobCount`
|
|
233
|
+
* @param {object|null} [input.plan] a required-check plan; OPTIONAL — with none, nothing
|
|
234
|
+
* is required and this degrades to a pure observation
|
|
235
|
+
* report rather than calling every red undeclared
|
|
236
|
+
* @param {string} [input.collectedAt]
|
|
237
|
+
*/
|
|
238
|
+
export function classifyHeadCheckSet({
|
|
239
|
+
repository,
|
|
240
|
+
headSha,
|
|
241
|
+
checkRuns = [],
|
|
242
|
+
statuses = [],
|
|
243
|
+
actionsRuns = [],
|
|
244
|
+
plan = null,
|
|
245
|
+
collectedAt = new Date().toISOString(),
|
|
246
|
+
}) {
|
|
247
|
+
const observations = [
|
|
248
|
+
...checkRuns.map(checkRunObservation),
|
|
249
|
+
...statuses.map(commitStatusObservation),
|
|
250
|
+
...actionsRuns.map(actionsRunObservation),
|
|
251
|
+
]
|
|
252
|
+
const required = requiredCheckNames(plan)
|
|
253
|
+
const requiredSet = new Set(required)
|
|
254
|
+
for (const entry of observations) entry.required = requiredSet.has(entry.name)
|
|
255
|
+
|
|
256
|
+
const observedNames = new Set(observations.map((entry) => entry.name))
|
|
257
|
+
const actionsObservations = observations.filter((entry) => entry.source === 'actions-run')
|
|
258
|
+
|
|
259
|
+
const red = observations.filter((entry) => entry.state === 'red')
|
|
260
|
+
const partition = {
|
|
261
|
+
requiredRed: red.filter((entry) => entry.required),
|
|
262
|
+
// The #1081 case. Informational by contract — see this file's header — but never silent.
|
|
263
|
+
undeclaredRed: red.filter((entry) => !entry.required),
|
|
264
|
+
neverRan: required
|
|
265
|
+
.filter((name) => !observedNames.has(name))
|
|
266
|
+
.map((name) => ({ name, ...absenceReason(observations, actionsObservations) })),
|
|
267
|
+
pending: observations.filter((entry) => entry.state === 'pending'),
|
|
268
|
+
neutral: observations.filter((entry) => entry.state === 'neutral'),
|
|
269
|
+
green: observations.filter((entry) => entry.state === 'green'),
|
|
270
|
+
}
|
|
271
|
+
const signatures = { startupFailures: startupFailures(observations) }
|
|
272
|
+
|
|
273
|
+
// Outcome ordering is the caller's decision order, and `green-with-undeclared-red` is
|
|
274
|
+
// deliberately its own value rather than folded into either neighbour: it is the state
|
|
275
|
+
// #1081 was in for seven hours, and it must be neither "failure" (it does not block)
|
|
276
|
+
// nor "green" (it is not).
|
|
277
|
+
let outcome = 'green'
|
|
278
|
+
if (partition.requiredRed.length) outcome = 'required-red'
|
|
279
|
+
else if (partition.neverRan.length) outcome = 'required-missing'
|
|
280
|
+
else if (partition.pending.length) outcome = 'pending'
|
|
281
|
+
else if (partition.undeclaredRed.length || signatures.startupFailures.length) outcome = 'green-with-undeclared-red'
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
version: HEAD_CHECK_SET_VERSION,
|
|
285
|
+
kind: HEAD_CHECK_SET_KIND,
|
|
286
|
+
repository,
|
|
287
|
+
headSha,
|
|
288
|
+
collectedAt,
|
|
289
|
+
planned: { required, planPresent: plan != null },
|
|
290
|
+
observations,
|
|
291
|
+
signatures,
|
|
292
|
+
partition,
|
|
293
|
+
summary: {
|
|
294
|
+
outcome,
|
|
295
|
+
counts: {
|
|
296
|
+
observations: observations.length,
|
|
297
|
+
checkRuns: checkRuns.length,
|
|
298
|
+
commitStatuses: statuses.length,
|
|
299
|
+
actionsRuns: actionsRuns.length,
|
|
300
|
+
requiredRed: partition.requiredRed.length,
|
|
301
|
+
undeclaredRed: partition.undeclaredRed.length,
|
|
302
|
+
neverRan: partition.neverRan.length,
|
|
303
|
+
pending: partition.pending.length,
|
|
304
|
+
startupFailures: signatures.startupFailures.length,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* True when the REQUIRED set — and only the required set — is unsatisfied.
|
|
312
|
+
*
|
|
313
|
+
* This is the whole of the blocking judgement, isolated here so that the one place a
|
|
314
|
+
* caller could turn undeclared red into a merge decision is a single named function
|
|
315
|
+
* rather than an exit-code expression buried in a CLI.
|
|
316
|
+
*/
|
|
317
|
+
export function blocksOnRequiredSet(artifact) {
|
|
318
|
+
return (artifact?.partition?.requiredRed?.length ?? 0) > 0
|
|
319
|
+
|| (artifact?.partition?.neverRan?.length ?? 0) > 0
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export function validateHeadCheckSetArtifact(artifact, { expectedHeadSha, label = 'headCheckSet' } = {}) {
|
|
323
|
+
const errors = []
|
|
324
|
+
if (!isObject(artifact)) return { ok: false, errors: [`${label} must be an object`] }
|
|
325
|
+
if (artifact.version !== HEAD_CHECK_SET_VERSION) errors.push(`${label}.version must be ${HEAD_CHECK_SET_VERSION}`)
|
|
326
|
+
if (artifact.kind !== HEAD_CHECK_SET_KIND) errors.push(`${label}.kind must be "${HEAD_CHECK_SET_KIND}"`)
|
|
327
|
+
if (!nonEmpty(artifact.repository) || !/^[^/\s]+\/[^/\s]+$/.test(artifact.repository)) errors.push(`${label}.repository must be owner/name`)
|
|
328
|
+
if (!nonEmpty(artifact.headSha) || !SHA.test(artifact.headSha)) errors.push(`${label}.headSha must be a full 40-character commit SHA`)
|
|
329
|
+
else if (expectedHeadSha && artifact.headSha !== expectedHeadSha) errors.push(`${label} is STALE: stamped ${artifact.headSha}, expected ${expectedHeadSha}`)
|
|
330
|
+
if (!Array.isArray(artifact.observations)) errors.push(`${label}.observations must be an array`)
|
|
331
|
+
else {
|
|
332
|
+
for (const [index, entry] of artifact.observations.entries()) {
|
|
333
|
+
const at = `${label}.observations[${index}]`
|
|
334
|
+
if (!isObject(entry)) { errors.push(`${at} must be an object`); continue }
|
|
335
|
+
if (!OBSERVATION_SOURCES.includes(entry.source)) errors.push(`${at}.source must be ${OBSERVATION_SOURCES.join('|')}`)
|
|
336
|
+
if (!nonEmpty(entry.name)) errors.push(`${at}.name must be a non-empty string`)
|
|
337
|
+
if (!OBSERVATION_STATES.includes(entry.state)) errors.push(`${at}.state must be ${OBSERVATION_STATES.join('|')}`)
|
|
338
|
+
if (typeof entry.required !== 'boolean') errors.push(`${at}.required must be boolean`)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (!isObject(artifact.partition)) errors.push(`${label}.partition must be an object`)
|
|
342
|
+
else {
|
|
343
|
+
for (const key of ['requiredRed', 'undeclaredRed', 'neverRan', 'pending', 'neutral', 'green']) {
|
|
344
|
+
if (!Array.isArray(artifact.partition[key])) errors.push(`${label}.partition.${key} must be an array`)
|
|
345
|
+
}
|
|
346
|
+
for (const [index, entry] of (artifact.partition.neverRan || []).entries()) {
|
|
347
|
+
const at = `${label}.partition.neverRan[${index}]`
|
|
348
|
+
if (!isObject(entry) || !nonEmpty(entry.name)) errors.push(`${at}.name must be a non-empty string`)
|
|
349
|
+
// The reason is the entire point of the row: an absence without one reads as
|
|
350
|
+
// "still queued" for all three of #1058's cases.
|
|
351
|
+
else if (!nonEmpty(entry.reason) || !nonEmpty(entry.detail)) errors.push(`${at} requires an actionable reason and detail`)
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (!isObject(artifact.signatures) || !Array.isArray(artifact.signatures.startupFailures)) errors.push(`${label}.signatures.startupFailures must be an array`)
|
|
355
|
+
if (!isObject(artifact.summary) || !nonEmpty(artifact.summary.outcome)) errors.push(`${label}.summary.outcome must be a non-empty string`)
|
|
356
|
+
return { ok: errors.length === 0, errors }
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function describe(entry) {
|
|
360
|
+
const detail = entry.source === 'actions-run'
|
|
361
|
+
? ` — run ${entry.runId ?? '?'}, event ${entry.event ?? '?'}, ${entry.jobCount === null ? 'job count unknown' : `${entry.jobCount} job(s)`}`
|
|
362
|
+
: ''
|
|
363
|
+
return `${entry.name} [${entry.source}] ${entry.conclusion ?? entry.status ?? 'pending'}${detail}`
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function renderHeadCheckSet(artifact) {
|
|
367
|
+
const lines = [
|
|
368
|
+
'<!-- generated by head-check-set.mjs — do not hand-edit; re-run collect -->',
|
|
369
|
+
`**Full check set at \`${artifact.headSha}\`** (${artifact.repository}, collected ${artifact.collectedAt})`,
|
|
370
|
+
'',
|
|
371
|
+
`- Outcome: **${artifact.summary?.outcome}** — ${artifact.summary?.counts?.observations ?? 0} observation(s) across `
|
|
372
|
+
+ `${artifact.summary?.counts?.checkRuns ?? 0} check-run(s), ${artifact.summary?.counts?.commitStatuses ?? 0} commit status(es), `
|
|
373
|
+
+ `${artifact.summary?.counts?.actionsRuns ?? 0} Actions run(s)`,
|
|
374
|
+
`- Required by the plan: ${artifact.planned?.planPresent ? (artifact.planned.required.join(', ') || 'none') : 'NO PLAN SUPPLIED — nothing is classified required, so this is an observation report only'}`,
|
|
375
|
+
]
|
|
376
|
+
const section = (title, rows) => {
|
|
377
|
+
if (!rows.length) return
|
|
378
|
+
lines.push(`- ${title}:`)
|
|
379
|
+
for (const row of rows) lines.push(` - ${row}`)
|
|
380
|
+
}
|
|
381
|
+
section('REQUIRED and red (blocking under the existing contract)', artifact.partition?.requiredRed?.map(describe) ?? [])
|
|
382
|
+
section(
|
|
383
|
+
'NOT required and red (informational — surfaced, never gated here; whether it should block belongs to `.mergify.yml` and the human)',
|
|
384
|
+
artifact.partition?.undeclaredRed?.map(describe) ?? [],
|
|
385
|
+
)
|
|
386
|
+
section(
|
|
387
|
+
'Required but never ran at all',
|
|
388
|
+
artifact.partition?.neverRan?.map((row) => `${row.name}: ${row.reason} — ${row.detail}`) ?? [],
|
|
389
|
+
)
|
|
390
|
+
section(
|
|
391
|
+
'Workflow runs that completed having executed ZERO jobs (the #1081 startup-failure signature)',
|
|
392
|
+
artifact.signatures?.startupFailures?.map((row) =>
|
|
393
|
+
`run ${row.runId} \`${row.name}\` (${row.conclusion}) executed no jobs`
|
|
394
|
+
+ `${row.nameEqualsPath ? ' and its name equals its file path — corroborating a workflow GitHub refused to parse' : ''}`) ?? [],
|
|
395
|
+
)
|
|
396
|
+
section('Pending', artifact.partition?.pending?.map(describe) ?? [])
|
|
397
|
+
return lines.join('\n')
|
|
398
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
|
|
7
|
+
import { isMainModule } from './main-module.mjs';
|
|
8
|
+
|
|
9
|
+
export const MANUAL_ONLY = 'manual-only';
|
|
10
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
11
|
+
|
|
12
|
+
function frontmatterBounds(contents) {
|
|
13
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(contents);
|
|
14
|
+
if (!match) throw new Error('SKILL.md must begin with YAML frontmatter');
|
|
15
|
+
return { body: match[1], end: match[0].length };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function manualOnlySkill(contents) {
|
|
19
|
+
const frontmatter = frontmatterBounds(contents);
|
|
20
|
+
const declarations = frontmatter.body.match(/^disable-model-invocation\s*:\s*.*$/gm) ?? [];
|
|
21
|
+
if (declarations.length > 1) throw new Error('SKILL.md repeats disable-model-invocation');
|
|
22
|
+
|
|
23
|
+
const body = declarations.length === 1
|
|
24
|
+
? frontmatter.body.replace(/^disable-model-invocation\s*:\s*.*$/m, 'disable-model-invocation: true')
|
|
25
|
+
: `${frontmatter.body}\ndisable-model-invocation: true`;
|
|
26
|
+
return `---\n${body}\n---\n${contents.slice(frontmatter.end)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function manualOnlyOpenAi(contents) {
|
|
30
|
+
const policyHeaders = contents.match(/^policy\s*:\s*$/gm) ?? [];
|
|
31
|
+
if (policyHeaders.length > 1) throw new Error('agents/openai.yaml repeats policy');
|
|
32
|
+
if (policyHeaders.length === 0) {
|
|
33
|
+
const prefix = contents.length === 0 || contents.endsWith('\n') ? contents : `${contents}\n`;
|
|
34
|
+
return `${prefix}policy:\n allow_implicit_invocation: false\n`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const lines = contents.split('\n');
|
|
38
|
+
const policyIndex = lines.findIndex((line) => /^policy\s*:\s*$/.test(line));
|
|
39
|
+
let policyEnd = lines.length;
|
|
40
|
+
for (let index = policyIndex + 1; index < lines.length; index += 1) {
|
|
41
|
+
if (/^[^\s#][^:]*\s*:/.test(lines[index])) {
|
|
42
|
+
policyEnd = index;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const declarations = lines
|
|
47
|
+
.slice(policyIndex + 1, policyEnd)
|
|
48
|
+
.filter((line) => /^\s+allow_implicit_invocation\s*:/.test(line));
|
|
49
|
+
if (declarations.length > 1) throw new Error('agents/openai.yaml repeats policy.allow_implicit_invocation');
|
|
50
|
+
if (declarations.length === 1) {
|
|
51
|
+
return lines.map((line, index) => (
|
|
52
|
+
index > policyIndex && index < policyEnd && /^\s+allow_implicit_invocation\s*:/.test(line)
|
|
53
|
+
? ' allow_implicit_invocation: false'
|
|
54
|
+
: line
|
|
55
|
+
)).join('\n');
|
|
56
|
+
}
|
|
57
|
+
lines.splice(policyIndex + 1, 0, ' allow_implicit_invocation: false');
|
|
58
|
+
return lines.join('\n');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function manualOnlyPolicyFindings(skillDirectory) {
|
|
62
|
+
const findings = [];
|
|
63
|
+
const skillPath = join(skillDirectory, 'SKILL.md');
|
|
64
|
+
const openaiPath = join(skillDirectory, 'agents', 'openai.yaml');
|
|
65
|
+
if (!existsSync(skillPath)) return ['SKILL.md is missing'];
|
|
66
|
+
const skill = readFileSync(skillPath, 'utf8');
|
|
67
|
+
const declarations = frontmatterBounds(skill).body.match(/^disable-model-invocation\s*:\s*true\s*$/gm) ?? [];
|
|
68
|
+
if (declarations.length !== 1) findings.push('SKILL.md must declare disable-model-invocation: true exactly once');
|
|
69
|
+
if (!existsSync(openaiPath)) {
|
|
70
|
+
findings.push('agents/openai.yaml is missing');
|
|
71
|
+
} else {
|
|
72
|
+
const openai = readFileSync(openaiPath, 'utf8');
|
|
73
|
+
const policies = openai.match(/^policy\s*:\s*$/gm) ?? [];
|
|
74
|
+
const implicit = openai.match(/^\s+allow_implicit_invocation\s*:\s*false\s*$/gm) ?? [];
|
|
75
|
+
if (policies.length !== 1 || implicit.length !== 1) {
|
|
76
|
+
findings.push('agents/openai.yaml must declare policy.allow_implicit_invocation: false exactly once');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Restore the reviewed upstream bytes for source-integrity hashing. The installed tree must first
|
|
83
|
+
// pass manualOnlyPolicyFindings; these exact trailing additions are the only intentional divergence.
|
|
84
|
+
export function reviewedSourceInjections(skillDirectory, policy) {
|
|
85
|
+
if (policy !== MANUAL_ONLY) return [];
|
|
86
|
+
const findings = manualOnlyPolicyFindings(skillDirectory);
|
|
87
|
+
if (findings.length > 0) throw new Error(findings.join('; '));
|
|
88
|
+
const skill = readFileSync(join(skillDirectory, 'SKILL.md'), 'utf8')
|
|
89
|
+
.replace(/^disable-model-invocation: true\n/m, '');
|
|
90
|
+
const openai = readFileSync(join(skillDirectory, 'agents', 'openai.yaml'), 'utf8')
|
|
91
|
+
.replace(/policy:\n allow_implicit_invocation: false\n?$/, '');
|
|
92
|
+
return [
|
|
93
|
+
{ relativePath: 'SKILL.md', contents: skill },
|
|
94
|
+
{ relativePath: 'agents/openai.yaml', contents: openai },
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function clearInvocationPolicy({ installName, policy, skillsRoot = join(homedir(), '.agents', 'skills') }) {
|
|
99
|
+
if (!SKILL_NAME.test(installName ?? '')) throw new Error(`invalid installed skill name ${JSON.stringify(installName)}`);
|
|
100
|
+
if (policy !== MANUAL_ONLY) throw new Error(`unsupported invocation policy ${JSON.stringify(policy)}`);
|
|
101
|
+
const skillDirectory = join(skillsRoot, installName);
|
|
102
|
+
const skillPath = join(skillDirectory, 'SKILL.md');
|
|
103
|
+
const openaiPath = join(skillDirectory, 'agents', 'openai.yaml');
|
|
104
|
+
if (!existsSync(skillPath) || !existsSync(openaiPath)) throw new Error(`installed skill is incomplete: ${skillDirectory}`);
|
|
105
|
+
const skill = readFileSync(skillPath, 'utf8');
|
|
106
|
+
const openai = readFileSync(openaiPath, 'utf8');
|
|
107
|
+
const hasSkillPolicy = /^disable-model-invocation\s*:/m.test(frontmatterBounds(skill).body);
|
|
108
|
+
const hasOpenAiPolicy = /^policy\s*:\s*$/m.test(openai) || /^\s+allow_implicit_invocation\s*:/m.test(openai);
|
|
109
|
+
if (!hasSkillPolicy && !hasOpenAiPolicy) {
|
|
110
|
+
return { installName, policy: 'implicit', skillDirectory, changed: false };
|
|
111
|
+
}
|
|
112
|
+
const injected = Object.fromEntries(reviewedSourceInjections(skillDirectory, policy)
|
|
113
|
+
.map((entry) => [entry.relativePath, entry.contents]));
|
|
114
|
+
writeFileSync(skillPath, injected['SKILL.md']);
|
|
115
|
+
writeFileSync(openaiPath, injected['agents/openai.yaml']);
|
|
116
|
+
return { installName, policy: 'implicit', skillDirectory, changed: true };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function applyInvocationPolicy({ installName, policy, skillsRoot = join(homedir(), '.agents', 'skills') }) {
|
|
120
|
+
if (!SKILL_NAME.test(installName ?? '')) throw new Error(`invalid installed skill name ${JSON.stringify(installName)}`);
|
|
121
|
+
if (policy !== MANUAL_ONLY) throw new Error(`unsupported invocation policy ${JSON.stringify(policy)}`);
|
|
122
|
+
const skillDirectory = join(skillsRoot, installName);
|
|
123
|
+
const skillPath = join(skillDirectory, 'SKILL.md');
|
|
124
|
+
if (!existsSync(skillPath)) throw new Error(`installed skill is missing: ${skillPath}`);
|
|
125
|
+
const openaiPath = join(skillDirectory, 'agents', 'openai.yaml');
|
|
126
|
+
|
|
127
|
+
const skillBefore = readFileSync(skillPath, 'utf8');
|
|
128
|
+
const skillAfter = manualOnlySkill(skillBefore);
|
|
129
|
+
if (skillAfter !== skillBefore) writeFileSync(skillPath, skillAfter);
|
|
130
|
+
|
|
131
|
+
mkdirSync(dirname(openaiPath), { recursive: true });
|
|
132
|
+
const openaiBefore = existsSync(openaiPath) ? readFileSync(openaiPath, 'utf8') : '';
|
|
133
|
+
const openaiAfter = manualOnlyOpenAi(openaiBefore);
|
|
134
|
+
if (openaiAfter !== openaiBefore) writeFileSync(openaiPath, openaiAfter);
|
|
135
|
+
|
|
136
|
+
const findings = manualOnlyPolicyFindings(skillDirectory);
|
|
137
|
+
if (findings.length > 0) throw new Error(findings.join('; '));
|
|
138
|
+
return { installName, policy, skillDirectory, changed: skillAfter !== skillBefore || openaiAfter !== openaiBefore };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function selectionEnablesTdd(env = process.env) {
|
|
142
|
+
const stateHome = env.XDG_STATE_HOME || join(env.HOME || homedir(), '.local', 'state');
|
|
143
|
+
const path = join(stateHome, '1aboveio-skills', 'selection.json');
|
|
144
|
+
if (!existsSync(path)) return true;
|
|
145
|
+
try {
|
|
146
|
+
const state = JSON.parse(readFileSync(path, 'utf8'));
|
|
147
|
+
if (state.tddImplicitInvocation === undefined) return true;
|
|
148
|
+
if (typeof state.tddImplicitInvocation !== 'boolean') {
|
|
149
|
+
throw new Error('tddImplicitInvocation must be a boolean');
|
|
150
|
+
}
|
|
151
|
+
return state.tddImplicitInvocation;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
throw new Error(`cannot read TDD invocation selection at ${path}: ${error.message}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function reconcileInvocationPolicy(options) {
|
|
158
|
+
return selectionEnablesTdd(options.env)
|
|
159
|
+
? clearInvocationPolicy(options)
|
|
160
|
+
: applyInvocationPolicy(options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function parseArgs(argv) {
|
|
164
|
+
const parsed = { installName: null, policy: null, skillsRoot: undefined, fromSelection: false };
|
|
165
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
166
|
+
const arg = argv[index];
|
|
167
|
+
if (arg === '--skill') parsed.installName = argv[++index];
|
|
168
|
+
else if (arg === '--policy') parsed.policy = argv[++index];
|
|
169
|
+
else if (arg === '--skills-root') parsed.skillsRoot = argv[++index];
|
|
170
|
+
else if (arg === '--from-selection') parsed.fromSelection = true;
|
|
171
|
+
else throw new Error(`unknown argument ${arg}`);
|
|
172
|
+
}
|
|
173
|
+
return parsed;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (isMainModule(import.meta.url)) {
|
|
177
|
+
try {
|
|
178
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
179
|
+
const result = parsed.fromSelection
|
|
180
|
+
? reconcileInvocationPolicy(parsed)
|
|
181
|
+
: applyInvocationPolicy(parsed);
|
|
182
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
183
|
+
} catch (error) {
|
|
184
|
+
process.stderr.write(`invocation-policy: ${error.message}\n`);
|
|
185
|
+
process.exitCode = 1;
|
|
186
|
+
}
|
|
187
|
+
}
|