skilldrop-cli 0.16.29 → 0.16.31
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/bin/skilldrop.js +160 -33
- package/catalogue.json +10 -4
- package/model-routing.json +24 -0
- package/package.json +1 -1
- package/packs/ai-engineering/skills/mcp-pairing/SKILL.md +93 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/eval_queries.json +13 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/evals.json +76 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/2/mcp.json +32 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/4/.mcp.json +47 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/4/docs/pr-loop.md +12 -0
- package/packs/ai-engineering/skills/mcp-pairing/evals/files/5/docs/oncall-triage.md +18 -0
- package/packs/ai-engineering/skills/mcp-pairing/examples/build-loop-github-jira-datadog.md +69 -0
- package/packs/ai-engineering/skills/mcp-pairing/manifest.json +17 -0
- package/packs/ai-engineering/skills/mcp-pairing/reference.md +136 -0
- package/packs/ai-engineering/skills/mcp-pairing/templates/mcp-pairing.md +43 -0
- package/packs/dev-team/loops/build/LOOP.md +4 -2
- package/packs/dev-team/loops/build/loop.json +2 -2
- package/packs/dev-team/loops/release/LOOP.md +7 -5
- package/packs/dev-team/loops/release/loop.json +2 -2
- package/packs/dev-team/skills/codebase-tour/SKILL.md +115 -0
- package/packs/dev-team/skills/codebase-tour/evals/eval_queries.json +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/evals.json +77 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/.github/workflows/ci.yml +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/README.md +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/openapi.yaml +21 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/package-lock.json +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/package.json +29 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/config.ts +20 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/domain/shipments/filter.ts +24 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/domain/shipments/repository.ts +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/errors.ts +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/generated/api-types.ts +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/http/handlers/shipments.ts +38 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/http/routes.ts +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/jobs/export-shipments.ts +22 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/src/server.ts +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/tests/domain/filter.test.ts +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/tests/http/shipments.test.ts +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/tsconfig.json +10 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/1/vitest.config.ts +5 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/.github/workflows/ci.yml +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/README.md +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/noxfile.py +14 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/pyproject.toml +22 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/__init__.py +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/_version.py +4 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/cli.py +32 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/detect.py +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/errors.py +2 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/money.py +14 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/__init__.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/acme.py +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/base.py +24 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/src/ledgerline/parsers/harbor.py +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/tests/fixtures/acme_sample.csv +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/tests/test_acme.py +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/2/tests/test_detect.py +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/.github/workflows/ci.yml +28 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/Makefile +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/README.md +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/cmd/tidepool/main.go +24 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/go.mod +5 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/config/config.go +38 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/dispatch/dispatcher.go +52 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/dispatch/dispatcher_test.go +42 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/dispatch/sender.go +32 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/replay/replay.go +31 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/db.go +35 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/query.sql +11 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/query.sql.go +30 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/schema.sql +6 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/internal/store/store_integration_test.go +21 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/3/sqlc.yaml +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/.env.example +4 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/.github/workflows/ci.yml +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/Makefile +16 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/README.md +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/data/rates.csv +4 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/pyproject.toml +19 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/scripts/gen_rates.py +29 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/__init__.py +0 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/api/__init__.py +0 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/api/preview.py +14 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/api/routes.py +36 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/config.py +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/discounts.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/generated/__init__.py +0 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/generated/rates_table.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/main.py +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/shipping.py +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/src/shipcalc/tax.py +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/tests/conftest.py +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/tests/unit/test_discounts.py +11 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/4/tests/unit/test_tax.py +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/.env.example +3 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/.github/workflows/ci.yml +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/README.md +18 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/package.json +13 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/openapi.json +30 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/package.json +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/db.js +19 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/flags.js +8 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/generated/schema.js +32 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/middleware/validate.js +20 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/routes/bookings.js +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/server.js +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/services/bookings.js +23 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/src/services/pricing.js +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/api/test/pricing.test.js +15 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/package.json +9 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/src/bookingForm.js +11 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/src/format.js +7 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/packages/web/test/format.test.js +12 -0
- package/packs/dev-team/skills/codebase-tour/evals/files/5/scripts/gen-schema.mjs +27 -0
- package/packs/dev-team/skills/codebase-tour/examples/refund-window.md +158 -0
- package/packs/dev-team/skills/codebase-tour/manifest.json +47 -0
- package/packs/dev-team/skills/codebase-tour/scripts/repo_facts.py +403 -0
- package/packs/dev-team/skills/codebase-tour/templates/codebase-tour.md +85 -0
- package/packs/dev-team/skills/dependency-upgrade-review/SKILL.md +101 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/eval_queries.json +11 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/evals.json +77 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/.github/workflows/ci.yml +20 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/pr.diff +87 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/quillmark-CHANGELOG.md +24 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/src/render/comment.js +6 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/src/render/note.js +8 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/1/test/note.test.js +12 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/.github/workflows/ci.yml +23 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/.github/workflows/release.yml +23 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/pr.diff +32 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/2/release-notes.md +20 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/.github/workflows/ci.yml +18 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/Dockerfile +8 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/PR.md +36 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/pr.diff +47 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/src/ingest/client.py +24 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/src/ingest/reader.py +32 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/tests/test_reader.py +15 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/4/upstream/quillstream-CHANGELOG.md +37 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/.github/workflows/ci.yml +22 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/.github/workflows/release.yml +25 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/.nvmrc +1 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/PR-412.md +16 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/PR-413.md +15 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/package.json +21 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/pr-412.diff +26 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/pr-413.diff +84 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/scripts/release.mjs +18 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/upstream/release-notary-CHANGELOG.md +16 -0
- package/packs/dev-team/skills/dependency-upgrade-review/evals/files/5/upstream/setup-toolchain-RELEASES.md +22 -0
- package/packs/dev-team/skills/dependency-upgrade-review/examples/inputs/ledgerline.diff +38 -0
- package/packs/dev-team/skills/dependency-upgrade-review/examples/ledgerline-tidyparse.md +91 -0
- package/packs/dev-team/skills/dependency-upgrade-review/manifest.json +50 -0
- package/packs/dev-team/skills/dependency-upgrade-review/reference.md +99 -0
- package/packs/dev-team/skills/dependency-upgrade-review/scripts/upgrade_diff.py +718 -0
- package/packs/dev-team/skills/refactor-plan/SKILL.md +168 -0
- package/packs/dev-team/skills/refactor-plan/evals/eval_queries.json +46 -0
- package/packs/dev-team/skills/refactor-plan/evals/evals.json +106 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/1/debt-register-row.md +5 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/1/in-flight-prs.md +7 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/1/order_service.py +74 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/1/test-coverage.txt +14 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/3/imports.txt +22 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/3/register.md +3 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/4/docs/open-prs.md +6 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/4/docs/tech-debt-register.md +7 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/4/reports/monthly_revenue.py +44 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/4/src/billing/invoice.py +233 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/4/src/partners/statement.py +29 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/4/tests/billing/test_payments.py +13 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/ci-notes.md +5 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/open-prs.txt +4 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/scripts/nightly-digest.js +36 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/src/auth/passwordReset.ts +16 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/src/notify/index.ts +2 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/src/notify/legacyMailer.ts +149 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/src/orders/onOrderShipped.ts +15 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/5/tests/notify/legacyMailer.test.ts +7 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/6/billing-service/src/main/kotlin/billing/DunningJob.kt +29 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/6/billing-service/src/main/kotlin/billing/InvoiceService.kt +157 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/6/billing-service/src/main/kotlin/billing/pdf/InvoicePdfRenderer.kt +36 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/6/billing-service/src/test/kotlin/billing/InvoiceServiceTest.kt +40 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/6/docs/adr-007-persistence.md +26 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/6/docs/open-prs.md +9 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/7/notes/open-work.md +19 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/7/web/src/components/CheckoutPanel.tsx +207 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/7/web/src/components/MiniCart.tsx +33 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/7/web/src/components/__tests__/CheckoutPanel.test.tsx +13 -0
- package/packs/dev-team/skills/refactor-plan/evals/files/7/web/src/pages/OrderReview.tsx +24 -0
- package/packs/dev-team/skills/refactor-plan/examples/search-ranker.md +104 -0
- package/packs/dev-team/skills/refactor-plan/manifest.json +36 -0
- package/packs/dev-team/skills/refactor-plan/reference.md +149 -0
- package/packs/dev-team/skills/refactor-plan/templates/refactor-plan.md +82 -0
- package/packs/dev-team/skills/rollout-plan/SKILL.md +157 -0
- package/packs/dev-team/skills/rollout-plan/evals/eval_queries.json +12 -0
- package/packs/dev-team/skills/rollout-plan/evals/evals.json +109 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/2/metrics-snapshot.txt +11 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/2/pr-description.md +28 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/4/PR_DESCRIPTION.md +24 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/4/metrics_snapshot.txt +7 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/5/docs/tax-engine-v2.md +24 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/6/flags/smart_reminders_v2.yaml +14 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/6/notes/push-pipeline.md +10 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/7/docs/ratelimiter-v2.md +21 -0
- package/packs/dev-team/skills/rollout-plan/evals/files/7/ops/traffic-summary.txt +9 -0
- package/packs/dev-team/skills/rollout-plan/examples/sync-engine-workspaces.md +102 -0
- package/packs/dev-team/skills/rollout-plan/manifest.json +35 -0
- package/packs/dev-team/skills/rollout-plan/reference.md +100 -0
- package/packs/dev-team/skills/rollout-plan/scripts/canary_math.py +261 -0
- package/packs/dev-team/skills/rollout-plan/templates/rollout-plan.md +50 -0
- package/packs/product-manager/loops/discover/LOOP.md +5 -4
- package/packs/product-manager/loops/discover/loop.json +2 -2
- package/packs/product-manager/skills/feedback-synthesis/SKILL.md +182 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/eval_queries.json +46 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/evals.json +76 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/1/interview-notes.md +47 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/1/nps-verbatims.csv +13 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/1/support-tickets.csv +36 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/3/churn-exit-survey.csv +11 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/3/sales-call-notes.md +55 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/4/csat_comments_q3.csv +17 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/4/support_tickets_q3.csv +49 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/5/app_reviews_last_60_days.csv +32 -0
- package/packs/product-manager/skills/feedback-synthesis/evals/files/5/interview_notes_round1.md +48 -0
- package/packs/product-manager/skills/feedback-synthesis/examples/booking-app-feedback.md +139 -0
- package/packs/product-manager/skills/feedback-synthesis/examples/inputs/booking-app-coded.csv +17 -0
- package/packs/product-manager/skills/feedback-synthesis/manifest.json +53 -0
- package/packs/product-manager/skills/feedback-synthesis/reference.md +89 -0
- package/packs/product-manager/skills/feedback-synthesis/scripts/theme_counts.py +355 -0
- package/packs/product-manager/skills/feedback-synthesis/templates/coding-sheet.csv +6 -0
- package/packs/product-manager/skills/feedback-synthesis/templates/synthesis.md +42 -0
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""List the facts a codebase tour cites, each with the file and line it came from.
|
|
3
|
+
|
|
4
|
+
Reads a repository and prints, to stdout:
|
|
5
|
+
- build and tool manifests found (package.json, pyproject.toml, Makefile, ...)
|
|
6
|
+
- commands the repo itself defines: package.json scripts, Makefile and justfile
|
|
7
|
+
targets, CI `run:` / `script:` steps, tox and nox sessions, pyproject entry points
|
|
8
|
+
- commands the README or CONTRIBUTING names that no manifest or CI file defines, and
|
|
9
|
+
paths they name that do not exist
|
|
10
|
+
- entry points (main functions, `__main__` guards, Dockerfile CMD/ENTRYPOINT, bin)
|
|
11
|
+
- test files grouped by directory, and test-runner config files
|
|
12
|
+
- files that say they are generated, vendored directories, and lockfiles
|
|
13
|
+
- environment variables the code reads, with the line that reads each
|
|
14
|
+
- the directories holding the most files
|
|
15
|
+
|
|
16
|
+
It is read-only: it opens files under the root it is given and writes nothing.
|
|
17
|
+
It cannot tell which command works; it tells you where each one is written down.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
python3 repo_facts.py <repo-root>
|
|
21
|
+
python3 repo_facts.py <repo-root> --json
|
|
22
|
+
python3 repo_facts.py <repo-root> --max 25 # cap items per section (default 40)
|
|
23
|
+
|
|
24
|
+
Exit codes: 0 facts printed, 2 bad input.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import argparse
|
|
28
|
+
import json
|
|
29
|
+
import os
|
|
30
|
+
import re
|
|
31
|
+
import sys
|
|
32
|
+
from collections import Counter, defaultdict
|
|
33
|
+
|
|
34
|
+
SKIP_DIRS = {".git", "node_modules", ".venv", "venv", "__pycache__", "dist", "build", ".tox",
|
|
35
|
+
".nox", "target", ".mypy_cache", ".pytest_cache", ".ruff_cache", ".next",
|
|
36
|
+
"coverage", ".gradle", ".idea", ".vscode", ".terraform"}
|
|
37
|
+
MANIFESTS = {"package.json", "pyproject.toml", "setup.cfg", "setup.py", "tox.ini", "noxfile.py",
|
|
38
|
+
"Makefile", "makefile", "GNUmakefile", "justfile", "Taskfile.yml", "go.mod",
|
|
39
|
+
"Cargo.toml", "pom.xml", "build.gradle", "build.gradle.kts", "Gemfile",
|
|
40
|
+
"composer.json", "Dockerfile", "docker-compose.yml", "docker-compose.yaml",
|
|
41
|
+
"compose.yml", "compose.yaml", "requirements.txt", "requirements-dev.txt",
|
|
42
|
+
".tool-versions", ".nvmrc", ".python-version", "CONTRIBUTING.md", "Procfile"}
|
|
43
|
+
LOCKFILES = {"package-lock.json", "yarn.lock", "pnpm-lock.yaml", "poetry.lock", "uv.lock",
|
|
44
|
+
"Pipfile.lock", "Cargo.lock", "go.sum", "Gemfile.lock", "composer.lock"}
|
|
45
|
+
VENDOR_DIRS = {"vendor", "third_party", "third-party", "vendored", "external"}
|
|
46
|
+
SOURCE_EXT = {".py", ".js", ".mjs", ".cjs", ".ts", ".tsx", ".jsx", ".go", ".rb", ".java",
|
|
47
|
+
".kt", ".rs", ".php", ".cs", ".sh", ".scala", ".swift"}
|
|
48
|
+
TEST_FILE = re.compile(r"(^test_.*\.py$|_test\.py$|_test\.go$|\.(test|spec)\.[cm]?[jt]sx?$|"
|
|
49
|
+
r"Tests?\.(java|kt|cs)$|_spec\.rb$|_test\.rb$)")
|
|
50
|
+
TEST_CONFIG = re.compile(r"^(pytest\.ini|conftest\.py|jest\.config\.\w+|vitest\.config\.\w+|"
|
|
51
|
+
r"karma\.conf\.\w+|\.mocharc\.\w+|phpunit\.xml(\.dist)?)$")
|
|
52
|
+
GENERATED = re.compile(r"(?i)(do not edit|@generated|code generated|auto-?generated|"
|
|
53
|
+
r"this file is generated|generated by|don't change)")
|
|
54
|
+
# Environment reads. `[.]` keeps each pattern literal without a backslash-dot sequence.
|
|
55
|
+
ENV_READS = [
|
|
56
|
+
re.compile(r"os[.]environ(?:[.]get)?\s*[\[(]\s*[\"']([A-Za-z_][A-Za-z0-9_]*)"),
|
|
57
|
+
re.compile(r"os[.]getenv\s*\(\s*[\"']([A-Za-z_][A-Za-z0-9_]*)"),
|
|
58
|
+
re.compile(r"process[.]env[.]([A-Za-z_][A-Za-z0-9_]*)"),
|
|
59
|
+
re.compile(r"process[.]env\[\s*[\"'`]([A-Za-z_][A-Za-z0-9_]*)"),
|
|
60
|
+
re.compile(r"os[.](?:Getenv|LookupEnv)\(\s*\"([A-Za-z_][A-Za-z0-9_]*)\""),
|
|
61
|
+
re.compile(r"ENV(?:[.]fetch\(|\[)\s*[\"']([A-Za-z_][A-Za-z0-9_]*)"),
|
|
62
|
+
re.compile(r"System[.]getenv\(\s*\"([A-Za-z_][A-Za-z0-9_]*)\""),
|
|
63
|
+
re.compile(r"env::var\(\s*\"([A-Za-z_][A-Za-z0-9_]*)\""),
|
|
64
|
+
]
|
|
65
|
+
RUNNERS = {"npm", "yarn", "pnpm", "make", "just", "nox", "tox"}
|
|
66
|
+
MAX_BYTES = 512 * 1024
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def walk(root):
|
|
70
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
71
|
+
dirnames[:] = sorted(d for d in dirnames if d not in SKIP_DIRS)
|
|
72
|
+
for name in sorted(filenames):
|
|
73
|
+
full = os.path.join(dirpath, name)
|
|
74
|
+
yield os.path.relpath(full, root).replace(os.sep, "/"), full
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def read_lines(full):
|
|
78
|
+
try:
|
|
79
|
+
if os.path.getsize(full) > MAX_BYTES:
|
|
80
|
+
return []
|
|
81
|
+
with open(full, encoding="utf-8", errors="replace") as fh:
|
|
82
|
+
return fh.read().splitlines()
|
|
83
|
+
except OSError:
|
|
84
|
+
return []
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def line_of(lines, pattern, start=0):
|
|
88
|
+
for i in range(start, len(lines)):
|
|
89
|
+
if re.search(pattern, lines[i]):
|
|
90
|
+
return i + 1
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def package_scripts(rel, lines, out, targets):
|
|
95
|
+
try:
|
|
96
|
+
doc = json.loads("\n".join(lines))
|
|
97
|
+
except ValueError:
|
|
98
|
+
return
|
|
99
|
+
for name, cmd in (doc.get("scripts") or {}).items():
|
|
100
|
+
n = line_of(lines, r'^\s*"%s"\s*:' % re.escape(name))
|
|
101
|
+
out.append({"command": "npm run %s" % name, "runs": cmd, "where": "%s:%d" % (rel, n)})
|
|
102
|
+
targets["npm"].add(name)
|
|
103
|
+
for key in ("main", "bin"):
|
|
104
|
+
if key in doc:
|
|
105
|
+
yield key, doc[key], "%s:%d" % (rel, line_of(lines, r'^\s*"%s"\s*:' % key))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def make_targets(rel, lines, out, targets, runner):
|
|
109
|
+
for i, line in enumerate(lines):
|
|
110
|
+
m = re.match(r"^([A-Za-z0-9][\w.-]*)\s*(?:[^:=\n]*)?:(?!=)", line)
|
|
111
|
+
if not m or m.group(1).startswith(".") or "=" in line.split(":")[0]:
|
|
112
|
+
continue
|
|
113
|
+
recipe = ""
|
|
114
|
+
for nxt in lines[i + 1:i + 4]:
|
|
115
|
+
if nxt.startswith(("\t", " ")) and nxt.strip():
|
|
116
|
+
recipe = nxt.strip()
|
|
117
|
+
break
|
|
118
|
+
out.append({"command": "%s %s" % (runner, m.group(1)), "runs": recipe,
|
|
119
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
120
|
+
targets[runner].add(m.group(1))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def ci_steps(rel, lines, out):
|
|
124
|
+
i = 0
|
|
125
|
+
while i < len(lines):
|
|
126
|
+
m = re.match(r"^(\s*)(?:-\s*)?run:\s*(.*)$", lines[i])
|
|
127
|
+
if m:
|
|
128
|
+
indent, value = len(m.group(1)), m.group(2).strip()
|
|
129
|
+
if value in ("|", ">", "|-", ">-", ""):
|
|
130
|
+
j = i + 1
|
|
131
|
+
while j < len(lines) and (not lines[j].strip() or
|
|
132
|
+
len(lines[j]) - len(lines[j].lstrip()) > indent):
|
|
133
|
+
if lines[j].strip() and not lines[j].strip().startswith("#"):
|
|
134
|
+
out.append({"command": lines[j].strip(), "where": "%s:%d" % (rel, j + 1)})
|
|
135
|
+
j += 1
|
|
136
|
+
i = j
|
|
137
|
+
continue
|
|
138
|
+
out.append({"command": value, "where": "%s:%d" % (rel, i + 1)})
|
|
139
|
+
i += 1
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def gitlab_steps(rel, lines, out):
|
|
143
|
+
inside = None
|
|
144
|
+
for i, line in enumerate(lines):
|
|
145
|
+
m = re.match(r"^(\s*)(before_script|script|after_script):\s*$", line)
|
|
146
|
+
if m:
|
|
147
|
+
inside = len(m.group(1))
|
|
148
|
+
continue
|
|
149
|
+
if inside is not None:
|
|
150
|
+
item = re.match(r"^(\s*)-\s+(.*)$", line)
|
|
151
|
+
if item and len(item.group(1)) >= inside:
|
|
152
|
+
out.append({"command": item.group(2).strip().strip("'\""), "where": "%s:%d" % (rel, i + 1)})
|
|
153
|
+
elif line.strip():
|
|
154
|
+
inside = None
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def tox_nox(rel, name, lines, out, targets):
|
|
158
|
+
if name == "tox.ini":
|
|
159
|
+
env = None
|
|
160
|
+
for i, line in enumerate(lines):
|
|
161
|
+
sec = re.match(r"^\[(testenv(?::(\S+))?)\]", line)
|
|
162
|
+
if sec:
|
|
163
|
+
env = sec.group(2) or "(default)"
|
|
164
|
+
if sec.group(2):
|
|
165
|
+
targets["tox"].add(sec.group(2))
|
|
166
|
+
elif env and re.match(r"^\s*commands\s*=", line):
|
|
167
|
+
cmd = line.split("=", 1)[1].strip()
|
|
168
|
+
out.append({"command": "tox -e %s" % env, "runs": cmd, "where": "%s:%d" % (rel, i + 1)})
|
|
169
|
+
else:
|
|
170
|
+
for i, line in enumerate(lines):
|
|
171
|
+
if re.match(r"^\s*@nox\.session", line):
|
|
172
|
+
fn = next((re.match(r"^\s*def\s+(\w+)", lines[j]) for j in range(i + 1, min(i + 4, len(lines)))
|
|
173
|
+
if re.match(r"^\s*def\s+\w+", lines[j])), None)
|
|
174
|
+
if fn:
|
|
175
|
+
targets["nox"].add(fn.group(1))
|
|
176
|
+
body = []
|
|
177
|
+
for j in range(i + 1, len(lines)):
|
|
178
|
+
if j > i + 1 and re.match(r"^(@|def |class )", lines[j]):
|
|
179
|
+
break
|
|
180
|
+
body.append(lines[j])
|
|
181
|
+
runs = [b.strip() for b in body if "session.run(" in b]
|
|
182
|
+
out.append({"command": "nox -s %s" % fn.group(1), "runs": "; ".join(runs),
|
|
183
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def pyproject(rel, lines, out, entries):
|
|
187
|
+
table = ""
|
|
188
|
+
for i, line in enumerate(lines):
|
|
189
|
+
sec = re.match(r"^\[([^\]]+)\]", line)
|
|
190
|
+
if sec:
|
|
191
|
+
table = sec.group(1).strip()
|
|
192
|
+
continue
|
|
193
|
+
kv = re.match(r"^\s*([\w.-]+)\s*=\s*(.+)$", line)
|
|
194
|
+
if not kv:
|
|
195
|
+
continue
|
|
196
|
+
if table in ("project.scripts", "tool.poetry.scripts"):
|
|
197
|
+
entries.append({"what": "console script `%s`" % kv.group(1), "target": kv.group(2).strip('"\''),
|
|
198
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
199
|
+
elif table.startswith("tool.hatch.envs.") and table.endswith(".scripts"):
|
|
200
|
+
out.append({"command": "hatch run %s" % kv.group(1), "runs": kv.group(2),
|
|
201
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
202
|
+
elif table == "tool.pytest.ini_options" and kv.group(1) in ("addopts", "testpaths", "markers"):
|
|
203
|
+
out.append({"command": "(pytest config) %s" % kv.group(1), "runs": kv.group(2),
|
|
204
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def doc_commands(root, rel, lines, targets, missing):
|
|
208
|
+
fence = False
|
|
209
|
+
for i, line in enumerate(lines):
|
|
210
|
+
if line.strip().startswith("```"):
|
|
211
|
+
fence = not fence
|
|
212
|
+
continue
|
|
213
|
+
indented = line.startswith((" ", "\t")) and not line.lstrip().startswith(("-", "*"))
|
|
214
|
+
if fence or indented:
|
|
215
|
+
candidates = [line.strip().lstrip("$ ").strip()]
|
|
216
|
+
else:
|
|
217
|
+
candidates = re.findall(r"`([^`]+)`", line)
|
|
218
|
+
for cand in candidates:
|
|
219
|
+
words = cand.split()
|
|
220
|
+
if len(words) > 1 and words[0] in ("python", "python3") and words[1].endswith(".py"):
|
|
221
|
+
if not os.path.exists(os.path.join(root, words[1])):
|
|
222
|
+
missing.append({"command": cand, "where": "%s:%d" % (rel, i + 1),
|
|
223
|
+
"why": "`%s` does not exist" % words[1]})
|
|
224
|
+
continue
|
|
225
|
+
if len(words) < 2 and not (words and words[0] in ("make", "just")):
|
|
226
|
+
continue
|
|
227
|
+
if not words or words[0] not in RUNNERS:
|
|
228
|
+
continue
|
|
229
|
+
runner, target = words[0], None
|
|
230
|
+
if runner in ("npm", "pnpm") and len(words) > 1:
|
|
231
|
+
target = words[2] if words[1] == "run" and len(words) > 2 else (
|
|
232
|
+
words[1] if words[1] in ("test", "start") else None)
|
|
233
|
+
runner = "npm"
|
|
234
|
+
elif runner == "yarn" and len(words) > 1 and words[1] not in ("install", "add"):
|
|
235
|
+
target = words[2] if words[1] == "run" and len(words) > 2 else words[1]
|
|
236
|
+
runner = "npm"
|
|
237
|
+
elif runner in ("make", "just"):
|
|
238
|
+
target = words[1] if len(words) > 1 else None
|
|
239
|
+
elif runner == "nox" and "-s" in words:
|
|
240
|
+
target = words[words.index("-s") + 1] if words.index("-s") + 1 < len(words) else None
|
|
241
|
+
elif runner == "tox" and "-e" in words:
|
|
242
|
+
target = words[words.index("-e") + 1] if words.index("-e") + 1 < len(words) else None
|
|
243
|
+
if runner in ("make", "just") and target is None:
|
|
244
|
+
if not targets[runner]:
|
|
245
|
+
missing.append({"command": cand, "where": "%s:%d" % (rel, i + 1),
|
|
246
|
+
"why": "no %s file defines any target" % runner})
|
|
247
|
+
continue
|
|
248
|
+
if target and target not in targets[runner]:
|
|
249
|
+
source = {"npm": "package.json scripts", "make": "a Makefile", "just": "a justfile",
|
|
250
|
+
"nox": "noxfile.py", "tox": "tox.ini"}[runner]
|
|
251
|
+
missing.append({"command": cand, "where": "%s:%d" % (rel, i + 1),
|
|
252
|
+
"why": "`%s` is not defined in %s" % (target, source)})
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def doc_paths(root, rel, lines, missing):
|
|
256
|
+
for i, line in enumerate(lines):
|
|
257
|
+
for cand in re.findall(r"`([^`\s]+)`", line):
|
|
258
|
+
looks_like_path = "/" in cand or re.search(r"\.(json|ya?ml|toml|ini|cfg|py|[jt]sx?|go|rb|sql|md)$", cand)
|
|
259
|
+
if not looks_like_path or cand.startswith(("http", "-", "@", "$")) or "*" in cand or "<" in cand:
|
|
260
|
+
continue
|
|
261
|
+
if not os.path.exists(os.path.join(root, cand.strip("/"))):
|
|
262
|
+
missing.append({"path": cand, "where": "%s:%d" % (rel, i + 1)})
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def collect(root):
|
|
266
|
+
facts = {"manifests": [], "commands": [], "doc_commands_not_found": [], "doc_paths_not_found": [],
|
|
267
|
+
"entry_points": [],
|
|
268
|
+
"tests": {}, "test_config": [], "generated": [], "vendored": [], "lockfiles": [],
|
|
269
|
+
"env_vars": [], "largest_dirs": []}
|
|
270
|
+
targets = defaultdict(set)
|
|
271
|
+
docs, dir_count, tests = [], Counter(), defaultdict(int)
|
|
272
|
+
for rel, full in walk(root):
|
|
273
|
+
name = os.path.basename(rel)
|
|
274
|
+
parts = rel.split("/")
|
|
275
|
+
dir_count["/".join(parts[:2]) if len(parts) > 2 else (parts[0] if len(parts) > 1 else ".")] += 1
|
|
276
|
+
vend = next((p for p in parts[:-1] if p in VENDOR_DIRS), None)
|
|
277
|
+
if vend:
|
|
278
|
+
vdir = "/".join(parts[:parts.index(vend) + 1])
|
|
279
|
+
if vdir not in facts["vendored"]:
|
|
280
|
+
facts["vendored"].append(vdir)
|
|
281
|
+
continue
|
|
282
|
+
if name in LOCKFILES:
|
|
283
|
+
facts["lockfiles"].append(rel)
|
|
284
|
+
continue
|
|
285
|
+
ext = os.path.splitext(name)[1].lower()
|
|
286
|
+
is_ci = rel.startswith(".github/workflows/") and ext in (".yml", ".yaml")
|
|
287
|
+
is_gitlab = name == ".gitlab-ci.yml"
|
|
288
|
+
if name in MANIFESTS or is_ci or is_gitlab or name.lower().startswith("readme"):
|
|
289
|
+
facts["manifests"].append(rel)
|
|
290
|
+
if TEST_FILE.search(name):
|
|
291
|
+
tests["/".join(parts[:-1]) or "."] += 1
|
|
292
|
+
if TEST_CONFIG.match(name):
|
|
293
|
+
facts["test_config"].append(rel)
|
|
294
|
+
wanted = (name in MANIFESTS or is_ci or is_gitlab or ext in SOURCE_EXT or name == ".gitattributes"
|
|
295
|
+
or name.lower().startswith("readme") or ext in (".md", ".yml", ".yaml", ".json", ".sql",
|
|
296
|
+
".toml", ".cfg", ".ini", ".proto"))
|
|
297
|
+
if not wanted:
|
|
298
|
+
continue
|
|
299
|
+
lines = read_lines(full)
|
|
300
|
+
if not lines:
|
|
301
|
+
continue
|
|
302
|
+
if name == "package.json":
|
|
303
|
+
for key, val, where in package_scripts(rel, lines, facts["commands"], targets):
|
|
304
|
+
facts["entry_points"].append({"what": "package.json %s" % key, "target": val, "where": where})
|
|
305
|
+
elif name in ("Makefile", "makefile", "GNUmakefile"):
|
|
306
|
+
make_targets(rel, lines, facts["commands"], targets, "make")
|
|
307
|
+
elif name == "justfile":
|
|
308
|
+
make_targets(rel, lines, facts["commands"], targets, "just")
|
|
309
|
+
elif is_ci:
|
|
310
|
+
ci_steps(rel, lines, facts["commands"])
|
|
311
|
+
elif is_gitlab:
|
|
312
|
+
gitlab_steps(rel, lines, facts["commands"])
|
|
313
|
+
elif name in ("tox.ini", "noxfile.py"):
|
|
314
|
+
tox_nox(rel, name, lines, facts["commands"], targets)
|
|
315
|
+
elif name == "pyproject.toml":
|
|
316
|
+
pyproject(rel, lines, facts["commands"], facts["entry_points"])
|
|
317
|
+
elif name == "Dockerfile":
|
|
318
|
+
for i, line in enumerate(lines):
|
|
319
|
+
if re.match(r"^\s*(CMD|ENTRYPOINT)\b", line):
|
|
320
|
+
facts["entry_points"].append({"what": "Dockerfile", "target": line.strip(),
|
|
321
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
322
|
+
elif name == ".gitattributes":
|
|
323
|
+
for i, line in enumerate(lines):
|
|
324
|
+
if "linguist-generated" in line or "linguist-vendored" in line:
|
|
325
|
+
facts["generated"].append({"path": line.split()[0], "marker": line.strip(),
|
|
326
|
+
"where": "%s:%d" % (rel, i + 1)})
|
|
327
|
+
if name.lower().startswith(("readme", "contributing")) and ext in (".md", ".rst", ""):
|
|
328
|
+
docs.append((rel, lines))
|
|
329
|
+
for i, line in enumerate(lines[:10]):
|
|
330
|
+
if ext in SOURCE_EXT | {".json", ".yml", ".yaml", ".sql", ".toml"} and GENERATED.search(line):
|
|
331
|
+
facts["generated"].append({"path": rel, "marker": line.strip()[:100], "where": "%s:%d" % (rel, i + 1)})
|
|
332
|
+
break
|
|
333
|
+
if ext in SOURCE_EXT:
|
|
334
|
+
for i, line in enumerate(lines):
|
|
335
|
+
if (re.match(r"^\s*func main\(\)", line) or re.match(r"^if __name__ == [\"']__main__[\"']", line)):
|
|
336
|
+
facts["entry_points"].append({"what": "main", "target": rel, "where": "%s:%d" % (rel, i + 1)})
|
|
337
|
+
for pat in ENV_READS:
|
|
338
|
+
for var in pat.findall(line):
|
|
339
|
+
facts["env_vars"].append({"name": var, "where": "%s:%d" % (rel, i + 1)})
|
|
340
|
+
for rel, lines in docs:
|
|
341
|
+
doc_commands(root, rel, lines, targets, facts["doc_commands_not_found"])
|
|
342
|
+
doc_paths(root, rel, lines, facts["doc_paths_not_found"])
|
|
343
|
+
facts["tests"] = dict(sorted(tests.items()))
|
|
344
|
+
facts["largest_dirs"] = [{"dir": d, "files": n} for d, n in dir_count.most_common(10)]
|
|
345
|
+
return facts
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def render(facts, cap):
|
|
349
|
+
out = []
|
|
350
|
+
|
|
351
|
+
def section(title, items, fmt, empty):
|
|
352
|
+
out.append("## %s" % title)
|
|
353
|
+
if not items:
|
|
354
|
+
out.append("- %s" % empty)
|
|
355
|
+
for item in items[:cap]:
|
|
356
|
+
out.append("- " + fmt(item))
|
|
357
|
+
if len(items) > cap:
|
|
358
|
+
out.append("- ... %d more (raise --max to see them)" % (len(items) - cap))
|
|
359
|
+
out.append("")
|
|
360
|
+
|
|
361
|
+
out.append("# Repository facts\n")
|
|
362
|
+
out.append("Where each fact is written down. Nothing here was run.\n")
|
|
363
|
+
section("Manifests, CI and docs", facts["manifests"], lambda m: "`%s`" % m, "none found")
|
|
364
|
+
section("Commands the repo defines", facts["commands"],
|
|
365
|
+
lambda c: "`%s`%s — %s" % (c["command"], (" → `%s`" % c["runs"]) if c.get("runs") else "", c["where"]),
|
|
366
|
+
"none found: no package scripts, Makefile, CI steps, tox or nox sessions")
|
|
367
|
+
section("Commands the docs name that nothing defines", facts["doc_commands_not_found"],
|
|
368
|
+
lambda c: "`%s` — %s — %s" % (c["command"], c["where"], c["why"]), "none")
|
|
369
|
+
section("Paths the docs name that do not exist", facts["doc_paths_not_found"],
|
|
370
|
+
lambda p: "`%s` — %s" % (p["path"], p["where"]), "none")
|
|
371
|
+
section("Entry points", facts["entry_points"],
|
|
372
|
+
lambda e: "%s: `%s` — %s" % (e["what"], e["target"], e["where"]), "none found")
|
|
373
|
+
tests = [{"dir": d, "n": n} for d, n in facts["tests"].items()]
|
|
374
|
+
section("Test files by directory", tests, lambda t: "`%s/` — %d file(s)" % (t["dir"], t["n"]),
|
|
375
|
+
"no test files found")
|
|
376
|
+
section("Test runner config", facts["test_config"], lambda t: "`%s`" % t, "none found")
|
|
377
|
+
section("Generated files", facts["generated"],
|
|
378
|
+
lambda g: "`%s` — %s — \"%s\"" % (g["path"], g["where"], g["marker"]), "no generated-file markers found")
|
|
379
|
+
section("Vendored directories", facts["vendored"], lambda v: "`%s/`" % v, "none")
|
|
380
|
+
section("Lockfiles", facts["lockfiles"], lambda f: "`%s`" % f, "none")
|
|
381
|
+
section("Environment variables the code reads", facts["env_vars"],
|
|
382
|
+
lambda e: "`%s` — %s" % (e["name"], e["where"]), "none found")
|
|
383
|
+
section("Largest directories (file count)", facts["largest_dirs"],
|
|
384
|
+
lambda d: "`%s` — %d" % (d["dir"], d["files"]), "empty")
|
|
385
|
+
return "\n".join(out)
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def main(argv=None):
|
|
389
|
+
ap = argparse.ArgumentParser(description="List a repo's commands, tests, generated files and env reads with file:line.")
|
|
390
|
+
ap.add_argument("root", help="repository root to read")
|
|
391
|
+
ap.add_argument("--json", action="store_true", help="print JSON instead of Markdown")
|
|
392
|
+
ap.add_argument("--max", type=int, default=40, help="items per section in Markdown (default 40)")
|
|
393
|
+
args = ap.parse_args(argv)
|
|
394
|
+
if not os.path.isdir(args.root):
|
|
395
|
+
print("error: %s is not a directory" % args.root, file=sys.stderr)
|
|
396
|
+
return 2
|
|
397
|
+
facts = collect(args.root)
|
|
398
|
+
print(json.dumps(facts, indent=2) if args.json else render(facts, max(1, args.max)))
|
|
399
|
+
return 0
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
if __name__ == "__main__":
|
|
403
|
+
sys.exit(main())
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Tour: {repo name}, for {the change, in one line}
|
|
2
|
+
|
|
3
|
+
_Read on {date}. Scope: {the path from the entry point to the change's far edge}. Skipped on purpose: {areas not on the path, e.g. "the admin UI, the billing service, deployment config"}._
|
|
4
|
+
|
|
5
|
+
{Any `[assumption]` lines go here, first, one per line.}
|
|
6
|
+
|
|
7
|
+
<!-- Citation key, for the writer (delete before sending):
|
|
8
|
+
`path:line` = read there · [inferred] = not verified, reason given ·
|
|
9
|
+
ran: passed / ran: failed (first error line) / read, not run · derived from <source> -->
|
|
10
|
+
|
|
11
|
+
## What matters for this change
|
|
12
|
+
|
|
13
|
+
<!-- 3–5 bullets. The things that change what the person does in the next hour: the README claim that's wrong, the second copy, the generated file, the test gap, the env var it won't start without. Each cites a file. -->
|
|
14
|
+
|
|
15
|
+
- {…} (`path:line`)
|
|
16
|
+
|
|
17
|
+
## Run it
|
|
18
|
+
|
|
19
|
+
<!-- ≤ ~15 lines. Commands only from CI / package scripts / Makefile / tox / nox / pyproject. CI's form wins. -->
|
|
20
|
+
|
|
21
|
+
| To | Command | Source | Status |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| Install | `{…}` | `{path:line}` | read, not run |
|
|
24
|
+
| Test (whole suite) | `{…}` | `{path:line}` | {ran: passed / ran: failed: … / read, not run} |
|
|
25
|
+
| Test (this area) | `{…}` | derived from `{path:line}` | {…} |
|
|
26
|
+
| Lint / typecheck | `{…}` | `{path:line}` | {…} |
|
|
27
|
+
| Run locally | `{…}` | `{path:line}` | {…} |
|
|
28
|
+
|
|
29
|
+
Needs: {env vars and services the commands need, each with where it is read or set, e.g. `DATABASE_URL` (`src/config.py:9`; CI sets it at `.github/workflows/ci.yml:14`)}.
|
|
30
|
+
|
|
31
|
+
## The path this change touches
|
|
32
|
+
|
|
33
|
+
<!-- ≤ 10 hops, entry point first, stop at the change's far edge. -->
|
|
34
|
+
|
|
35
|
+
1. `{path:line}` `{function}`: {what happens here}
|
|
36
|
+
2. …
|
|
37
|
+
|
|
38
|
+
## Where the change goes
|
|
39
|
+
|
|
40
|
+
<!-- Files and functions, each with the sibling pattern that justifies it. Then everything that must change with it. -->
|
|
41
|
+
|
|
42
|
+
- `{path}` `{function}`: {what to add} because {sibling pattern, cited}
|
|
43
|
+
- Must change with it: {spec + regenerate command / registry entry / second copy}, (`path:line`)
|
|
44
|
+
|
|
45
|
+
## Conventions the code follows
|
|
46
|
+
|
|
47
|
+
<!-- ≤ ~15 lines. Only the ones this change will hit. Each from code, cited. -->
|
|
48
|
+
|
|
49
|
+
- **Errors:** {…} (`path:line`)
|
|
50
|
+
- **Tests:** {location, naming, fixtures} (`path`)
|
|
51
|
+
- **Config:** {how it is read} (`path:line`)
|
|
52
|
+
- **Naming:** {…} (`path:line`)
|
|
53
|
+
|
|
54
|
+
## Traps
|
|
55
|
+
|
|
56
|
+
<!-- Every check reports. "none found" is an answer. -->
|
|
57
|
+
|
|
58
|
+
- **Generated:** {file} from {source}, regenerate with `{command}` (`path:line`); CI drift check: {yes, `path:line` / none}
|
|
59
|
+
- **Second copy:** {where the same logic lives} (`path:line`), or none found (searched for {identifiers})
|
|
60
|
+
- **Untested on the path:** {functions} or none
|
|
61
|
+
- **Tests the default command skips:** {marker / build tag / glob} (`path:line`) or none
|
|
62
|
+
- **Env vars and flags on the path:** `{NAME}` default {…} (`path:line`)
|
|
63
|
+
- **Vendored:** {…} or none
|
|
64
|
+
|
|
65
|
+
## Where the README is wrong
|
|
66
|
+
|
|
67
|
+
<!-- One line each, both citations. Omit the section only if every README claim checked out, and say "README checked: no conflicts." in the scope line instead. -->
|
|
68
|
+
|
|
69
|
+
- README says {…} (`README.md:{n}`); the code {…} (`path:line`). Follow the code.
|
|
70
|
+
|
|
71
|
+
## Tests for this area
|
|
72
|
+
|
|
73
|
+
- Covered by: `{test file}` ({what it asserts})
|
|
74
|
+
- Run just these: `{derived command}` (derived from `{path:line}`)
|
|
75
|
+
- Not covered: {functions with no test}, or "every function on the path has a test"
|
|
76
|
+
|
|
77
|
+
## First step
|
|
78
|
+
|
|
79
|
+
{Do X in `path`; run `command`; expect {result}.}
|
|
80
|
+
|
|
81
|
+
## Open questions for a maintainer
|
|
82
|
+
|
|
83
|
+
<!-- ≤ 5. Each answerable in a sentence, each pointing at the evidence that raised it. -->
|
|
84
|
+
|
|
85
|
+
1. {…} (`path:line`)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dependency-upgrade-review
|
|
3
|
+
description: Give a merge verdict on a dependency-upgrade pull request (Dependabot, Renovate or a hand-made bump) across npm, pip, Go, Cargo and Maven lockfiles and GitHub Actions pins. Reads the release notes for every skipped version, lists what the lockfile changes beyond the PR title (transitive bumps, new and removed packages, install scripts, registry changes), checks that each SHA pin is the commit its release tag points to, says whether CI ran the changed code, finds the repo's uses of changed APIs and writes the rollback, ending in MERGE, MERGE AFTER CHECKS or DO NOT MERGE. Use when the user says "review this Dependabot PR", "is this Renovate bump safe to merge", "can I merge this dependency upgrade", "check this lockfile diff", or "is this action SHA pin right".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dependency-upgrade-review
|
|
7
|
+
|
|
8
|
+
A dependency bump is someone else's code entering the repo under a one-line title. This skill reads it the way a careful maintainer does: every release between the old and new version, every line of the lockfile, every pin, and the tests that would have caught a break. The verdict follows from those checks, not from a green badge. Reviewing the repo's own code changes is `pre-merge-review`; writing the notes for a release of this project is `release-notes`; planning a framework migration across many PRs is `migration-plan`.
|
|
9
|
+
|
|
10
|
+
## How to respond
|
|
11
|
+
|
|
12
|
+
**Four rules come before the steps and outrank them:**
|
|
13
|
+
|
|
14
|
+
- **Answer what was asked, first.** Open with the answer, the decision or the artifact, in plain words. Scores, matrices, frameworks and tags come after it, and anything that doesn't change the answer is cut.
|
|
15
|
+
- **Use only what you were given.** Don't add facts, names, numbers, incidents, history, steps or sections the input doesn't contain. What you need and don't have is left out of the artifact and listed once at the end under "To confirm".
|
|
16
|
+
- **Deliver from what you have.** When the request gives you something to work on, state your assumptions in a line and produce the result. When it gives you nothing to work on, ask for it in one or two plain sentences and say what you will do once you have it.
|
|
17
|
+
- **Write for someone who has never heard of this skill.** No skill names, no paths or scripts from this folder, no internal terms, and nothing about how the run was set up. A next step is one plain sentence at the end that describes the work.
|
|
18
|
+
- **For this skill:** A check nobody ran is an open check, written as the command that runs it. It is never reported as passed, and "CI is green" closes only the checks CI actually ran.
|
|
19
|
+
|
|
20
|
+
1. **Get the diff, the notes and the code, asking once.** Three inputs: the PR diff covering manifests, lockfiles and workflow files (`gh pr diff 212` or `git diff origin/main...HEAD`); the release notes or changelog for every version between old and new; the repo, or at least the files that import the package and the CI workflow files. Ask for what is missing in one message. With network access, fetch missing notes from the package's releases page or changelog; without it, each missing release becomes an open check.
|
|
21
|
+
|
|
22
|
+
2. **Run the diff script first.** It lists every changed dependency with old → new, semver class, direct or transitive, and flags added and removed packages, install hooks, native-code hints, registry changes, licence changes and pins, then prints a floor verdict.
|
|
23
|
+
```bash
|
|
24
|
+
# Claude Code
|
|
25
|
+
python3 "${CLAUDE_SKILL_DIR}/scripts/upgrade_diff.py" pr.diff --title "Bump quillmark from 3.4.1 to 4.1.0"
|
|
26
|
+
# Other IDEs (from the skill folder)
|
|
27
|
+
python3 scripts/upgrade_diff.py pr.diff --title "Bump quillmark from 3.4.1 to 4.1.0"
|
|
28
|
+
```
|
|
29
|
+
It reads stdin with `-` (`gh pr diff 212 | python3 scripts/upgrade_diff.py -`). If it reports version lines out of context, re-run on `git diff -U12`. If no script can run, read every lockfile hunk by hand with the per-ecosystem notes in [`reference.md`](reference.md).
|
|
30
|
+
|
|
31
|
+
3. **List everything the lockfile changes beyond the title.** The title names one package; the lockfile is the truth. Report each of: transitive bumps (with class), packages added, packages removed, new install scripts (`hasInstallScript: true`, a `preinstall` / `install` / `postinstall` / `prepare` hook, pnpm `requiresBuild: true`), new native or binary dependencies (`prebuild-install`, `node-gyp`, a Cargo `-sys` crate), a changed `resolved` / `source` / index URL, and a maintainer or publisher change when the input shows one. ✅ *"Also changes: `entity-codec` 2.1.0 → 3.0.2 (major, licence MIT → MPL-2.0), adds `quill-native-highlight` 1.0.0 with an install script, removes `html-escape-lite`."* ❌ *"Bumps quillmark to 4.1.0."*
|
|
32
|
+
|
|
33
|
+
4. **Class each jump.** Major, minor or patch from the version numbers. Below 1.0 the minor is the breaking number: 0.8.3 → 0.9.0 is a breaking jump, and below 0.1 so is the patch. A Go module path gaining `/v2` is a new module, not a bump. A prerelease target (`-rc.1`, `-beta`) or a downgrade is never a plain MERGE. A moving major tag (`@v2` → `@v3`) spans every v2.x after the one in use plus v3.0.0 to the current v3.
|
|
34
|
+
|
|
35
|
+
5. **Read every release between old and new, not only the target.** For each direct dependency, list every release after the old version up to and including the new one, and pull four things from each: breaking changes, deprecations, security fixes, licence changes. Transitive majors, 0.x breaking jumps and new packages get the same reading; transitive patch and minor bumps are listed, not read. Name each release whose notes are missing. ✅ *"3.5.0 fixes an attribute-injection bug in link titles and deprecates `setOptions()`; 4.0.0 removes `renderInline()` and turns `sanitize` off by default; 4.0.1 and 4.1.0 are fixes and an optional highlighter."* ❌ *"4.1.0 adds a native highlighter. Looks fine."* A security fix is a reason to take the upgrade; when the full jump is blocked, name the smallest version that carries the fix as the alternative.
|
|
36
|
+
|
|
37
|
+
6. **Search the repo for every API the notes change.** For each removed or renamed function, changed signature and changed default, search and report `file:line` for each hit, or "no hits". A changed default hits every call that doesn't pass the option. ✅ *"`src/render/note.js:7` calls `quillmark.render(markdown)` with no `sanitize`, so from 4.0.0 note bodies pass raw HTML through."* ❌ *"Check whether the code uses `renderInline`."* Give the search you ran (`git grep -n -E "renderInline|setOptions|render\(" -- '*.js' '*.ts'`); with no repo in hand, give that command as an open check and claim neither hits nor no hits.
|
|
38
|
+
|
|
39
|
+
7. **Verify every pin; an unverified SHA is an open check.** For a SHA-pinned action (or any dependency pinned to a commit), the pinned SHA must be the commit the release tag points to:
|
|
40
|
+
```bash
|
|
41
|
+
git ls-remote https://github.com/<owner>/<repo> refs/tags/<tag> 'refs/tags/<tag>^{}'
|
|
42
|
+
```
|
|
43
|
+
For an annotated tag the `^{}` line is the commit; the other line is the tag object. For a lightweight tag the single line is the commit. Not run means `UNVERIFIED`, never "looks right": a SHA from a fork of the repo also resolves under the upstream path. A SHA with no version comment is an unknown release. A tag-only pin (`@v3`) moved to another tag is weaker than a SHA, because the tag can be moved after review; say so and give the command that finds the SHA to pin. Say what the job hands the action: a `secrets.*` token, `id-token: write` or `contents: write` raises the stakes of every pin in that job.
|
|
44
|
+
|
|
45
|
+
8. **Say whether CI ran the changed code.** A green check proves what it ran and nothing else. For each changed package or action, name the workflow job and test file that exercise it, or say nothing does. The usual gaps: an action or tool used only in a workflow triggered by a tag push, a release, a schedule or `workflow_dispatch`, which the PR never ran; a library used only in a file no test imports (a step 6 hit with no test); a test that runs the code but not the changed behaviour. ✅ *"`ci / test` runs `test/note.test.js`, which renders Markdown with no raw HTML, so the `sanitize` change is untested; nothing imports `src/render/comment.js`."* ❌ *"All checks pass."*
|
|
46
|
+
|
|
47
|
+
9. **Write the rollback.** The exact revert: `git revert` of the merge commit, or the pin-back for the ecosystem (`npm install quillmark@3.4.1`, `poetry add tidyparse@2.2.0`, `go get <module>@v0.8.3 && go mod tidy`, `cargo update -p <crate> --precise <old>`, the old `uses:` line) with the lockfile regenerated and committed. Then name what a revert does not undo: a lockfile format migration, a data, cache or schema format the new version wrote, an artifact built or published with it (a registry version cannot be republished), and a security fix that rolling back reopens. When the old version sits inside a fixed advisory's range, the pin-back target is the first fixed version, not the old one: ✅ *"pin back to 3.5.0"* ❌ *"pin back to 3.4.1"* when 3.5.0 fixed a bug affecting 3.0.0 to 3.4.x. Per-ecosystem commands are in [`reference.md`](reference.md).
|
|
48
|
+
|
|
49
|
+
10. **Derive the verdict from the checks.** Exactly one of:
|
|
50
|
+
- **DO NOT MERGE** when any holds: a removed or changed API is still used and the PR does not fix it; a new install script or native binary download nobody has confirmed is expected; a dependency source or registry moved to an unexplained host; a SHA that does not match its tag; a pin weakened (SHA to tag, tag to branch); a licence the project cannot ship; a target version an advisory names as vulnerable; a red CI check.
|
|
51
|
+
- **MERGE AFTER CHECKS** when none of those holds but any of these does: an unverified SHA; a major or 0.x breaking jump; a release whose notes were not read; changed code no CI job runs; a deprecated API still used; a new package or transitive major; a licence change that needs sign-off; a moved tag-only pin; no repo to search. Each check is a command or a concrete action.
|
|
52
|
+
- **MERGE** only when every check above is closed, with the evidence in the reply.
|
|
53
|
+
The script's floor is a minimum. Raise it on what steps 5 to 8 find. Lower DO NOT MERGE only when the user confirms the install script or new source is expected, and say so in the reply.
|
|
54
|
+
|
|
55
|
+
11. **Reply in this order, in one message:** the verdict and the one reason that decides it; 🟥 blockers, 🟧 checks before merge and 🟨 notes, each with `file:line` or the command; a short table of what the PR changes, including everything beyond the title; the rollback; "To confirm". A routine PR fits in about 300 words. Lead with what blocks, not with the package history.
|
|
56
|
+
|
|
57
|
+
**Non-interactive runs** (subagent, CI, headless): with no diff, emit `BLOCKED: need the PR diff covering the manifests, lockfiles and workflow files (gh pr diff <number>)`. Missing release notes, repo or CI files do not block: each becomes a named open check, the verdict is at best MERGE AFTER CHECKS, and the gap is stated first as `[assumption] notes for <versions> not read` or `[assumption] CI coverage unknown, treated as none`.
|
|
58
|
+
|
|
59
|
+
## Useful references in this skill
|
|
60
|
+
|
|
61
|
+
- [`reference.md`](reference.md): reading each ecosystem's lockfile diff, where install scripts and sources show up, how to list the releases between two versions, SHA verification details, and per-ecosystem rollback commands with what a revert leaves behind
|
|
62
|
+
- [`scripts/upgrade_diff.py`](scripts/upgrade_diff.py): stdlib parser for a unified diff of manifests, lockfiles and workflow files; prints changes, flags, pin checks and a floor verdict (exit 2 on bad input)
|
|
63
|
+
- [`examples/ledgerline-tidyparse.md`](examples/ledgerline-tidyparse.md): worked example, a Poetry patch bump with a transitive bump, real script output and the review that reaches MERGE
|
|
64
|
+
|
|
65
|
+
## Quality bar
|
|
66
|
+
|
|
67
|
+
- **Exactly one verdict, first, and it follows from the checks.** Any unverified SHA, added install script, or removed API still in use rules out MERGE.
|
|
68
|
+
- **Every release between old and new is accounted for:** read, with its breaking changes, deprecations, security fixes and licence changes named, or listed as unread.
|
|
69
|
+
- **Everything the lockfile changes beyond the title is listed:** transitive bumps, added and removed packages, install scripts, native code, source changes.
|
|
70
|
+
- **Every changed API has a search result:** `file:line` hits, "no hits", or the command to run when there is no repo.
|
|
71
|
+
- **Every SHA pin is verified or marked UNVERIFIED with the `git ls-remote` command;** tag-only pins are called weaker.
|
|
72
|
+
- **CI coverage is named per changed package:** the job and test that exercise it, or "nothing does".
|
|
73
|
+
- **A rollback with the exact command** and what a revert does not undo.
|
|
74
|
+
- **No invented versions, advisories, APIs, files or test names.** Everything cited appears in the diff, the notes or the repo supplied.
|
|
75
|
+
|
|
76
|
+
## When to use this skill
|
|
77
|
+
|
|
78
|
+
- ✅ A Dependabot or Renovate PR is open and someone asks whether to merge it
|
|
79
|
+
- ✅ A hand-made bump of one or more packages, with its lockfile diff
|
|
80
|
+
- ✅ A GitHub Actions version bump, SHA-pinned or tag-pinned
|
|
81
|
+
- ✅ A grouped update PR where the title hides how many packages moved
|
|
82
|
+
- ✅ Checking whether a lockfile diff brings in install scripts, new registries or new packages
|
|
83
|
+
|
|
84
|
+
## When NOT to use this skill
|
|
85
|
+
|
|
86
|
+
- ❌ Reviewing a PR whose substance is the repo's own code change: use `pre-merge-review`
|
|
87
|
+
- ❌ Writing the release notes or changelog for this project's next version: use `release-notes`
|
|
88
|
+
- ❌ Planning a multi-step framework or runtime migration (a major framework version across many services): use `migration-plan`
|
|
89
|
+
- ❌ Scanning installed skills for supply-chain patterns: that is the `skilldrop scan` command
|
|
90
|
+
- ❌ Choosing which library to adopt in the first place: this reviews a version change, not a selection
|
|
91
|
+
|
|
92
|
+
## Anti-patterns to avoid
|
|
93
|
+
|
|
94
|
+
- ❌ **Reading only the target version's notes.** The breaking change usually lives in a release the PR skipped.
|
|
95
|
+
- ❌ **Trusting the title.** "Bump X from 1 to 2" says nothing about the twelve transitive packages that moved with it.
|
|
96
|
+
- ❌ **Calling a SHA pin fine because it is a SHA.** A SHA proves nothing until it matches the release tag.
|
|
97
|
+
- ❌ **"CI is green, ship it."** Release workflows, publish steps and untested code paths never ran on the PR.
|
|
98
|
+
- ❌ **"No breaking changes affect us" without a search.** Show the grep and its hits, or say it was not run.
|
|
99
|
+
- ❌ **A rollback that is only "revert the PR".** Name the lockfile regeneration and what a revert leaves behind.
|
|
100
|
+
- ❌ **Reciting the changelog.** Report the releases that change the verdict; one line covers the rest.
|
|
101
|
+
- ❌ **Hedged verdicts.** "Probably safe" is not a verdict; pick one of the three and give the reason.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
[
|
|
2
|
+
{ "query": "Dependabot wants to bump express from 4.19 to 5.0, can I merge the PR?", "should_trigger": true },
|
|
3
|
+
{ "query": "review this Renovate PR, it updates 14 packages in package-lock.json", "should_trigger": true },
|
|
4
|
+
{ "query": "is this actions/checkout SHA pin in the dependabot PR actually the v4.2.2 commit?", "should_trigger": true },
|
|
5
|
+
{ "query": "I bumped pydantic and regenerated poetry.lock, anything in the lockfile diff I should worry about before merging?", "should_trigger": true },
|
|
6
|
+
{ "query": "check this go.mod / go.sum diff from the deps update PR, CI is green", "should_trigger": true },
|
|
7
|
+
{ "query": "review my PR that adds rate limiting to the checkout API before I merge", "should_trigger": false },
|
|
8
|
+
{ "query": "write the release notes for our 3.2.0 release from the merged PRs", "should_trigger": false },
|
|
9
|
+
{ "query": "plan our migration from React 17 to React 19 across the four frontend apps", "should_trigger": false },
|
|
10
|
+
{ "query": "scan the skills I'm about to install for risky scripts", "should_trigger": false }
|
|
11
|
+
]
|