@soleur/opencode 0.0.0-stage → 3.354.2
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/.claude-plugin/agents.manifest.json +476 -0
- package/.claude-plugin/plugin.json +42 -0
- package/README.md +44 -2
- package/agents/community/.gitkeep +0 -0
- package/agents/engineering/cto.md +87 -0
- package/agents/engineering/design/ddd-architect.md +95 -0
- package/agents/engineering/discovery/agent-finder.md +214 -0
- package/agents/engineering/discovery/functional-discovery.md +182 -0
- package/agents/engineering/infra/infra-security.md +151 -0
- package/agents/engineering/infra/platform-strategist.md +109 -0
- package/agents/engineering/infra/terraform-architect.md +171 -0
- package/agents/engineering/prompt-engineer.md +37 -0
- package/agents/engineering/research/best-practices-researcher.md +115 -0
- package/agents/engineering/research/framework-docs-researcher.md +93 -0
- package/agents/engineering/research/git-history-analyzer.md +53 -0
- package/agents/engineering/research/learnings-researcher.md +285 -0
- package/agents/engineering/research/repo-research-analyst.md +118 -0
- package/agents/engineering/review/agent-native-reviewer.md +279 -0
- package/agents/engineering/review/architecture-strategist.md +61 -0
- package/agents/engineering/review/code-quality-analyst.md +92 -0
- package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
- package/agents/engineering/review/data-integrity-guardian.md +82 -0
- package/agents/engineering/review/data-migration-expert.md +98 -0
- package/agents/engineering/review/deployment-verification-agent.md +183 -0
- package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
- package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
- package/agents/engineering/review/legacy-code-expert.md +55 -0
- package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
- package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
- package/agents/engineering/review/performance-oracle.md +130 -0
- package/agents/engineering/review/security-sentinel.md +167 -0
- package/agents/engineering/review/semgrep-sast.md +36 -0
- package/agents/engineering/review/test-design-reviewer.md +150 -0
- package/agents/engineering/review/user-impact-reviewer.md +70 -0
- package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
- package/agents/finance/budget-analyst.md +29 -0
- package/agents/finance/cfo.md +44 -0
- package/agents/finance/financial-reporter.md +30 -0
- package/agents/finance/revenue-analyst.md +30 -0
- package/agents/legal/clo.md +115 -0
- package/agents/legal/legal-compliance-auditor.md +110 -0
- package/agents/legal/legal-document-generator.md +134 -0
- package/agents/marketing/analytics-analyst.md +25 -0
- package/agents/marketing/brand-architect.md +181 -0
- package/agents/marketing/cmo.md +76 -0
- package/agents/marketing/conversion-optimizer.md +19 -0
- package/agents/marketing/copywriter.md +20 -0
- package/agents/marketing/fact-checker.md +70 -0
- package/agents/marketing/growth-strategist.md +145 -0
- package/agents/marketing/paid-media-strategist.md +28 -0
- package/agents/marketing/pricing-strategist.md +17 -0
- package/agents/marketing/programmatic-seo-specialist.md +25 -0
- package/agents/marketing/retention-strategist.md +23 -0
- package/agents/marketing/seo-aeo-analyst.md +164 -0
- package/agents/operations/coo.md +50 -0
- package/agents/operations/ops-advisor.md +78 -0
- package/agents/operations/ops-provisioner.md +101 -0
- package/agents/operations/ops-research.md +52 -0
- package/agents/operations/service-automator.md +278 -0
- package/agents/product/business-validator.md +206 -0
- package/agents/product/competitive-intelligence.md +89 -0
- package/agents/product/cpo.md +63 -0
- package/agents/product/design/ux-design-lead.md +209 -0
- package/agents/product/spec-flow-analyzer.md +122 -0
- package/agents/sales/cro.md +44 -0
- package/agents/sales/deal-architect.md +29 -0
- package/agents/sales/outbound-strategist.md +29 -0
- package/agents/sales/pipeline-analyst.md +29 -0
- package/agents/support/cco.md +48 -0
- package/agents/support/community-manager.md +570 -0
- package/agents/support/ticket-triage.md +70 -0
- package/bin/soleur-opencode.js +29 -0
- package/commands/go.md +660 -0
- package/commands/help.md +273 -0
- package/commands/sync.md +977 -0
- package/commands/version.md +103 -0
- package/hooks/antigravity-hooks.json +84 -0
- package/hooks/antigravity-session-start.sh +15 -0
- package/hooks/bare-root-cwd-guard.sh +131 -0
- package/hooks/browser-snapshot-credential-guard.sh +200 -0
- package/hooks/codex-session-start.sh +9 -0
- package/hooks/compaction-state.sh +525 -0
- package/hooks/destructive-command-guard.sh +1387 -0
- package/hooks/devin-session-start.sh +90 -0
- package/hooks/ext-filter-detect.sh +171 -0
- package/hooks/hooks.json +133 -0
- package/hooks/lib/hook-tool-kind.sh +24 -0
- package/hooks/lib/log-rotation.sh +176 -0
- package/hooks/lib/shell-argv.pl +576 -0
- package/hooks/memory-backstop.sh +1114 -0
- package/hooks/operator-stage-approval.sh +391 -0
- package/hooks/stop-hook.sh +367 -0
- package/hooks/unkept-promise-hook.sh +383 -0
- package/hooks/version-banner.sh +127 -0
- package/hooks/welcome-hook.sh +50 -0
- package/install.js +29 -0
- package/lib/agent-registry.ts +154 -0
- package/lib/c4-canonical-cli.mjs +34 -0
- package/lib/c4-canonical.mjs +46 -0
- package/lib/c4-from-components.ts +554 -0
- package/lib/go-routing.ts +81 -0
- package/lib/grok-inspect-contract.ts +311 -0
- package/lib/harness-model-map.ts +101 -0
- package/lib/harness-parity.ts +726 -0
- package/lib/harness-tool-map.ts +180 -0
- package/lib/harness.ts +716 -0
- package/lib/heartbeat-live-reconcile.ts +1153 -0
- package/lib/heartbeat-manifest.ts +361 -0
- package/lib/kb-coverage.ts +252 -0
- package/lib/pr-merge-poll.ts +103 -0
- package/lib/workflow-fidelity.ts +388 -0
- package/opencode/INSTRUCTIONS.md +171 -0
- package/opencode/agents/engineering/cto.md +10 -0
- package/opencode/agents/engineering/design/ddd-architect.md +10 -0
- package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
- package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
- package/opencode/agents/engineering/infra/infra-security.md +10 -0
- package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
- package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
- package/opencode/agents/engineering/prompt-engineer.md +10 -0
- package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
- package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
- package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
- package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
- package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
- package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
- package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
- package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
- package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
- package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
- package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
- package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
- package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
- package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
- package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
- package/opencode/agents/engineering/review/performance-oracle.md +10 -0
- package/opencode/agents/engineering/review/security-sentinel.md +10 -0
- package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
- package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
- package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
- package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
- package/opencode/agents/finance/budget-analyst.md +10 -0
- package/opencode/agents/finance/cfo.md +10 -0
- package/opencode/agents/finance/financial-reporter.md +10 -0
- package/opencode/agents/finance/revenue-analyst.md +10 -0
- package/opencode/agents/legal/clo.md +10 -0
- package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
- package/opencode/agents/legal/legal-document-generator.md +10 -0
- package/opencode/agents/marketing/analytics-analyst.md +10 -0
- package/opencode/agents/marketing/brand-architect.md +10 -0
- package/opencode/agents/marketing/cmo.md +10 -0
- package/opencode/agents/marketing/conversion-optimizer.md +10 -0
- package/opencode/agents/marketing/copywriter.md +10 -0
- package/opencode/agents/marketing/fact-checker.md +10 -0
- package/opencode/agents/marketing/growth-strategist.md +10 -0
- package/opencode/agents/marketing/paid-media-strategist.md +10 -0
- package/opencode/agents/marketing/pricing-strategist.md +10 -0
- package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
- package/opencode/agents/marketing/retention-strategist.md +10 -0
- package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
- package/opencode/agents/operations/coo.md +10 -0
- package/opencode/agents/operations/ops-advisor.md +10 -0
- package/opencode/agents/operations/ops-provisioner.md +10 -0
- package/opencode/agents/operations/ops-research.md +10 -0
- package/opencode/agents/operations/service-automator.md +10 -0
- package/opencode/agents/product/business-validator.md +10 -0
- package/opencode/agents/product/competitive-intelligence.md +10 -0
- package/opencode/agents/product/cpo.md +10 -0
- package/opencode/agents/product/design/ux-design-lead.md +10 -0
- package/opencode/agents/product/spec-flow-analyzer.md +10 -0
- package/opencode/agents/sales/cro.md +10 -0
- package/opencode/agents/sales/deal-architect.md +10 -0
- package/opencode/agents/sales/outbound-strategist.md +10 -0
- package/opencode/agents/sales/pipeline-analyst.md +10 -0
- package/opencode/agents/support/cco.md +10 -0
- package/opencode/agents/support/community-manager.md +10 -0
- package/opencode/agents/support/ticket-triage.md +10 -0
- package/opencode/commands/go.md +10 -0
- package/opencode/commands/help.md +10 -0
- package/opencode/commands/sync.md +10 -0
- package/opencode/commands/version.md +11 -0
- package/opencode/opencode.json +8 -0
- package/opencode/plugin.ts +818 -0
- package/package.json +36 -4
- package/scripts/admin-merge-ready.sh +545 -0
- package/scripts/admin-merge-ready.test.sh +753 -0
- package/scripts/affected-tests.sh +908 -0
- package/scripts/affected-tests.test.sh +1797 -0
- package/scripts/alpha-metrics.sh +78 -0
- package/scripts/alpha-metrics.test.sh +115 -0
- package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
- package/scripts/audit-flag-flip.sh +107 -0
- package/scripts/check-red-on-main.sh +316 -0
- package/scripts/ci-head-verdict.sh +411 -0
- package/scripts/cloud-detect.sh +193 -0
- package/scripts/delegation-verify.sh +657 -0
- package/scripts/delegation-verify.test.sh +1424 -0
- package/scripts/deploy-arm.sh +475 -0
- package/scripts/domain-model-drift.sh +419 -0
- package/scripts/emit-decision.sh +144 -0
- package/scripts/emit-decision.test.sh +144 -0
- package/scripts/ext-filter-divergence-corpus.txt +15 -0
- package/scripts/ext-filter-divergence.sh +189 -0
- package/scripts/generate-c4-from-components.ts +442 -0
- package/scripts/grok-fidelity-gate.sh +68 -0
- package/scripts/grok-pre-push-gate.sh +232 -0
- package/scripts/harness-discovery-smoke.ts +906 -0
- package/scripts/harness-parity-census.ts +92 -0
- package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
- package/scripts/install-opencode-adapter.ts +509 -0
- package/scripts/lib/affected-tests/common.sh +365 -0
- package/scripts/lib/affected-tests/go.sh +157 -0
- package/scripts/lib/affected-tests/js.sh +188 -0
- package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
- package/scripts/lib/affected-tests/python.sh +185 -0
- package/scripts/lib/context-sanitize.sh +49 -0
- package/scripts/lib/domain-model-lib.sh +180 -0
- package/scripts/lib/ext-filter-grammar.tsv +34 -0
- package/scripts/lib/operator-script.sh +1236 -0
- package/scripts/lib/proc.sh +580 -0
- package/scripts/lib/session-state.sh +748 -0
- package/scripts/lib/tmp-classify.sh +843 -0
- package/scripts/lib/wrapper-boundary.sh +47 -0
- package/scripts/lint-ratchet.py +1547 -0
- package/scripts/monitor-pr-checks.sh +441 -0
- package/scripts/pipeline-tally.sh +756 -0
- package/scripts/pipeline-tally.test.sh +740 -0
- package/scripts/plugin-version.sh +528 -0
- package/scripts/precommit-guard.sh +115 -0
- package/scripts/precommit-guard.test.sh +254 -0
- package/scripts/reconcile-live-heartbeats.ts +705 -0
- package/scripts/render-c4-model.sh +217 -0
- package/scripts/resolve-git-root.sh +55 -0
- package/scripts/resolve-regenerable-conflicts.sh +363 -0
- package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
- package/scripts/ruff-requirements.txt +22 -0
- package/scripts/run-in-pid-namespace.sh +98 -0
- package/scripts/run-in-pid-namespace.test.sh +290 -0
- package/scripts/scan-ancestor-signal-helpers.py +556 -0
- package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
- package/scripts/setup-ralph-loop.sh +238 -0
- package/scripts/sync-cursor-name-map.ts +316 -0
- package/scripts/sync-grok-agent-compat.ts +188 -0
- package/scripts/sync-npm-package.ts +165 -0
- package/scripts/sync-opencode-adapter.ts +498 -0
- package/scripts/sync-pr-behind.sh +647 -0
- package/scripts/sync-pr-behind.test.sh +252 -0
- package/scripts/taste-profile-update.sh +180 -0
- package/scripts/taste-profile-update.test.sh +167 -0
- package/scripts/write-budget-marker.sh +23 -0
- package/scripts/write-kb-coverage.ts +113 -0
- package/skills/admin-ip-refresh/SKILL.md +81 -0
- package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
- package/skills/agent-browser/SKILL.md +698 -0
- package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
- package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
- package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
- package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
- package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
- package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
- package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
- package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
- package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
- package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
- package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
- package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
- package/skills/agent-native-architecture/SKILL.md +479 -0
- package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
- package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
- package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
- package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
- package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
- package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
- package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
- package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
- package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
- package/skills/agent-native-architecture/references/product-implications.md +478 -0
- package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
- package/skills/agent-native-architecture/references/self-modification.md +294 -0
- package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
- package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
- package/skills/agent-native-audit/SKILL.md +300 -0
- package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
- package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
- package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
- package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/skills/architecture/SKILL.md +436 -0
- package/skills/architecture/references/adr-template.md +154 -0
- package/skills/architecture/references/likec4-reference.md +136 -0
- package/skills/architecture/references/nfr-reference.md +126 -0
- package/skills/archive-kb/SKILL.md +86 -0
- package/skills/archive-kb/scripts/archive-kb.sh +300 -0
- package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
- package/skills/atdd-developer/SKILL.md +65 -0
- package/skills/brainstorm/SKILL.md +701 -0
- package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
- package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
- package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
- package/skills/brainstorm/references/ui-surface-terms.md +42 -0
- package/skills/brainstorm-techniques/SKILL.md +231 -0
- package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
- package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
- package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
- package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
- package/skills/campaign-calendar/SKILL.md +145 -0
- package/skills/cf-token-scope/SKILL.md +164 -0
- package/skills/cf-token-scope/references/widen-playbook.md +114 -0
- package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
- package/skills/changelog/SKILL.md +142 -0
- package/skills/code-to-prd/SKILL.md +66 -0
- package/skills/code-to-prd/references/banner-template.md +12 -0
- package/skills/code-to-prd/references/prd-template.md +41 -0
- package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
- package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
- package/skills/code-to-prd/test/fixture/.env.example +7 -0
- package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
- package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
- package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
- package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
- package/skills/code-to-prd/test/fixture/package.json +6 -0
- package/skills/cohort-status/SKILL.md +62 -0
- package/skills/community/SKILL.md +210 -0
- package/skills/community/scripts/bsky-community.sh +644 -0
- package/skills/community/scripts/bsky-setup.sh +631 -0
- package/skills/community/scripts/community-router.sh +93 -0
- package/skills/community/scripts/discord-community.sh +487 -0
- package/skills/community/scripts/discord-setup.sh +784 -0
- package/skills/community/scripts/github-community.sh +706 -0
- package/skills/community/scripts/hn-community.sh +233 -0
- package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
- package/skills/community/scripts/linkedin-community.sh +750 -0
- package/skills/community/scripts/linkedin-setup.sh +758 -0
- package/skills/community/scripts/x-community.sh +890 -0
- package/skills/community/scripts/x-setup.sh +713 -0
- package/skills/community/test/community-argv.test.sh +2922 -0
- package/skills/community/test/github-community.test.sh +981 -0
- package/skills/competitive-analysis/SKILL.md +69 -0
- package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
- package/skills/compound/SKILL.md +673 -0
- package/skills/compound/scripts/token-efficiency-report.sh +334 -0
- package/skills/compound/test/phase-16.test.sh +379 -0
- package/skills/compound-capture/SKILL.md +791 -0
- package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
- package/skills/compound-capture/assets/resolution-template.md +116 -0
- package/skills/compound-capture/references/yaml-schema.md +67 -0
- package/skills/compound-capture/schema.yaml +181 -0
- package/skills/constraint-scaffold/SKILL.md +175 -0
- package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
- package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
- package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
- package/skills/constraint-scaffold/references/shared-runner.template +135 -0
- package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
- package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
- package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
- package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
- package/skills/constraint-scaffold/test/generator.test.sh +93 -0
- package/skills/constraint-scaffold/test/parity.test.sh +285 -0
- package/skills/content-writer/SKILL.md +242 -0
- package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
- package/skills/cron-delete/SKILL.md +56 -0
- package/skills/cron-list/SKILL.md +54 -0
- package/skills/deepen-plan/SKILL.md +937 -0
- package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
- package/skills/deploy/SKILL.md +115 -0
- package/skills/deploy/references/hetzner-setup.md +67 -0
- package/skills/deploy/scripts/deploy.sh +37 -0
- package/skills/deploy-docs/SKILL.md +95 -0
- package/skills/dhh-rails-style/SKILL.md +203 -0
- package/skills/dhh-rails-style/references/architecture.md +717 -0
- package/skills/dhh-rails-style/references/controllers.md +323 -0
- package/skills/dhh-rails-style/references/frontend.md +556 -0
- package/skills/dhh-rails-style/references/gems.md +316 -0
- package/skills/dhh-rails-style/references/models.md +388 -0
- package/skills/dhh-rails-style/references/testing.md +354 -0
- package/skills/discord-content/SKILL.md +126 -0
- package/skills/docs-site/SKILL.md +214 -0
- package/skills/drain-labeled-backlog/SKILL.md +203 -0
- package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
- package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
- package/skills/drain-prs/SKILL.md +143 -0
- package/skills/drain-prs/scripts/triage-prs.sh +192 -0
- package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
- package/skills/dspy-ruby/SKILL.md +634 -0
- package/skills/dspy-ruby/assets/config-template.rb +359 -0
- package/skills/dspy-ruby/assets/module-template.rb +326 -0
- package/skills/dspy-ruby/assets/signature-template.rb +143 -0
- package/skills/dspy-ruby/references/core-concepts.md +268 -0
- package/skills/dspy-ruby/references/optimization.md +623 -0
- package/skills/dspy-ruby/references/providers.md +335 -0
- package/skills/eval-harness/README.md +194 -0
- package/skills/eval-harness/SKILL.md +157 -0
- package/skills/eval-harness/enums/go-routes.json +13 -0
- package/skills/eval-harness/enums/incident-threshold.json +5 -0
- package/skills/eval-harness/enums/lane.json +5 -0
- package/skills/eval-harness/enums/tool-selection.json +20 -0
- package/skills/eval-harness/enums/triage-levels.json +5 -0
- package/skills/eval-harness/gated-skills.json +34 -0
- package/skills/eval-harness/models.generated.json +5 -0
- package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
- package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
- package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
- package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
- package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
- package/skills/eval-harness/prompts/go-baseline.txt +6 -0
- package/skills/eval-harness/prompts/go-skill.txt +21 -0
- package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
- package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
- package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
- package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
- package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
- package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
- package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
- package/skills/eval-harness/prompts/triage-skill.txt +10 -0
- package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
- package/skills/eval-harness/scripts/extract-block.cjs +87 -0
- package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
- package/skills/eval-harness/scripts/gen-models.sh +41 -0
- package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
- package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
- package/skills/eval-harness/scripts/parse-label.cjs +93 -0
- package/skills/eval-harness/scripts/verdict.cjs +132 -0
- package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
- package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
- package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
- package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
- package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
- package/skills/eval-harness/test/eval-gate.test.sh +132 -0
- package/skills/eval-harness/test/extract-block.test.sh +87 -0
- package/skills/eval-harness/test/gate-classification.test.sh +77 -0
- package/skills/eval-harness/test/gen-models.test.sh +75 -0
- package/skills/eval-harness/test/measure-classification.test.sh +74 -0
- package/skills/eval-harness/test/parse-label.test.sh +129 -0
- package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
- package/skills/eval-harness/test/verdict.test.sh +123 -0
- package/skills/every-style-editor/SKILL.md +142 -0
- package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/skills/feature-tweet/SKILL.md +199 -0
- package/skills/feature-video/SKILL.md +412 -0
- package/skills/feature-video/scripts/check_deps.sh +281 -0
- package/skills/file-todos/SKILL.md +267 -0
- package/skills/file-todos/assets/todo-template.md +166 -0
- package/skills/fix-issue/SKILL.md +278 -0
- package/skills/fix-issue/references/agent-authored-exclusion.md +120 -0
- package/skills/fix-issue/references/exclude-label-jq-snippet.md +97 -0
- package/skills/flag-bootstrap/SETUP.md +142 -0
- package/skills/flag-create/SKILL.md +145 -0
- package/skills/flag-create/scripts/create.sh +273 -0
- package/skills/flag-delete/SKILL.md +167 -0
- package/skills/flag-delete/scripts/delete.sh +288 -0
- package/skills/flag-list/SKILL.md +99 -0
- package/skills/flag-list/scripts/list.sh +275 -0
- package/skills/flag-set-role/SKILL.md +229 -0
- package/skills/flag-set-role/scripts/flip.sh +774 -0
- package/skills/frontend-anti-slop/SKILL.md +106 -0
- package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
- package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
- package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
- package/skills/frontend-design/SKILL.md +77 -0
- package/skills/gdpr-gate/NOTICE +136 -0
- package/skills/gdpr-gate/SKILL.md +341 -0
- package/skills/gdpr-gate/references/fields.md +160 -0
- package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
- package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
- package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
- package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
- package/skills/gdpr-gate/references/layers/frontend.md +249 -0
- package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
- package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
- package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
- package/skills/gdpr-gate/references/legal-consent.md +140 -0
- package/skills/gdpr-gate/references/non-negotiables.md +60 -0
- package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
- package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
- package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
- package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
- package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
- package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
- package/skills/gemini-imagegen/SKILL.md +283 -0
- package/skills/gemini-imagegen/requirements.txt +5 -0
- package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
- package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
- package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
- package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
- package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
- package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
- package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
- package/skills/git-worktree/SKILL.md +534 -0
- package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
- package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
- package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
- package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
- package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
- package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
- package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
- package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
- package/skills/go/SKILL.md +54 -0
- package/skills/growth/SKILL.md +164 -0
- package/skills/harvest-debt/SKILL.md +78 -0
- package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
- package/skills/heal-skill/SKILL.md +173 -0
- package/skills/help/SKILL.md +46 -0
- package/skills/incident/NOTICE +39 -0
- package/skills/incident/SKILL.md +395 -0
- package/skills/incident/scripts/dry-run.sh +448 -0
- package/skills/incident/scripts/redact-engine.py +412 -0
- package/skills/incident/scripts/redact-sentinel.sh +44 -0
- package/skills/incident/templates/pir.md +139 -0
- package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
- package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
- package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
- package/skills/incident/test/fixtures/positive-corpus.md +87 -0
- package/skills/incident/test/redact-sentinel.test.sh +1420 -0
- package/skills/invoice/SKILL.md +206 -0
- package/skills/kb-glossary/SKILL.md +71 -0
- package/skills/kb-glossary/references/glossary-format.md +111 -0
- package/skills/kb-glossary/references/rejected-request-register.md +115 -0
- package/skills/kb-search/SKILL.md +276 -0
- package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
- package/skills/legal-audit/SKILL.md +161 -0
- package/skills/legal-generate/NOTICE +242 -0
- package/skills/legal-generate/SKILL.md +244 -0
- package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
- package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
- package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
- package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
- package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
- package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
- package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
- package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
- package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
- package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
- package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
- package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
- package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
- package/skills/linear-fetch/SKILL.md +247 -0
- package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
- package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
- package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
- package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
- package/skills/linear-fetch/test/parity.test.sh +112 -0
- package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
- package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
- package/skills/merge-pr/SKILL.md +670 -0
- package/skills/model-launch-review/SKILL.md +255 -0
- package/skills/model-launch-review/scripts/audit-models.sh +501 -0
- package/skills/one-shot/SKILL.md +316 -0
- package/skills/one-shot/references/token-discipline.md +74 -0
- package/skills/operator-bootstrap/SKILL.md +412 -0
- package/skills/operator-bootstrap/template.sh +439 -0
- package/skills/operator-digest/SKILL.md +287 -0
- package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
- package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
- package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
- package/skills/operator-rephrase/SKILL.md +98 -0
- package/skills/pencil-setup/SKILL.md +201 -0
- package/skills/pencil-setup/scripts/check_deps.sh +556 -0
- package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
- package/skills/pencil-setup/scripts/package-lock.json +1172 -0
- package/skills/pencil-setup/scripts/package.json +14 -0
- package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
- package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
- package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
- package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
- package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
- package/skills/plan/SKILL.md +1140 -0
- package/skills/plan/references/differential-migration-testing.md +185 -0
- package/skills/plan/references/plan-community-discovery.md +42 -0
- package/skills/plan/references/plan-founder-check.md +137 -0
- package/skills/plan/references/plan-functional-overlap.md +25 -0
- package/skills/plan/references/plan-host-fanout.md +51 -0
- package/skills/plan/references/plan-issue-templates.md +779 -0
- package/skills/plan/references/plan-network-outage-checklist.md +131 -0
- package/skills/plan/references/plan-scope-check.md +126 -0
- package/skills/plan/references/plan-sharp-edges.md +331 -0
- package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
- package/skills/plan/references/webapp-cwv-observability.md +143 -0
- package/skills/plan-review/SKILL.md +91 -0
- package/skills/plan-review/lib/named-panel.mjs +58 -0
- package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
- package/skills/postmerge/SKILL.md +642 -0
- package/skills/postmerge/references/deploy-status-debugging.md +141 -0
- package/skills/postmerge/references/graceful-degradation.md +20 -0
- package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
- package/skills/preflight/SKILL.md +1553 -0
- package/skills/preflight/references/check-13-founder-check.md +286 -0
- package/skills/preflight/scripts/founder-check.py +1640 -0
- package/skills/preflight/scripts/parse-form-a.awk +107 -0
- package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
- package/skills/product-roadmap/SKILL.md +357 -0
- package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
- package/skills/provision-cloudflare/SKILL.md +67 -0
- package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
- package/skills/provision-doppler/SKILL.md +58 -0
- package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
- package/skills/provision-github/SKILL.md +59 -0
- package/skills/provision-github/scripts/provision-github.sh +300 -0
- package/skills/provision-hetzner/SKILL.md +76 -0
- package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
- package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
- package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
- package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
- package/skills/qa/SKILL.md +263 -0
- package/skills/qa/references/browser-preflight.md +22 -0
- package/skills/questionnaire-generate/SKILL.md +328 -0
- package/skills/questionnaire-generate/references/questionnaire.template +60 -0
- package/skills/rclone/SKILL.md +162 -0
- package/skills/rclone/scripts/check_setup.sh +63 -0
- package/skills/release-announce/SKILL.md +65 -0
- package/skills/release-docs/SKILL.md +92 -0
- package/skills/reproduce-bug/SKILL.md +358 -0
- package/skills/resolve-debt/SKILL.md +85 -0
- package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
- package/skills/resolve-parallel/SKILL.md +45 -0
- package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
- package/skills/resolve-pr-parallel/SKILL.md +68 -0
- package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
- package/skills/resolve-todo-parallel/SKILL.md +57 -0
- package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
- package/skills/review/SKILL.md +1620 -0
- package/skills/review/references/anti-slop-scanner-hook.md +40 -0
- package/skills/review/references/defect-classes-migrations.md +9 -0
- package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
- package/skills/review/references/review-e2e-testing.md +116 -0
- package/skills/review/references/review-evidence-comment.md +36 -0
- package/skills/review/references/review-todo-structure.md +165 -0
- package/skills/review/references/risk-tier-and-fix-rounds.md +97 -0
- package/skills/review/references/semgrep-custom-rules.yaml +174 -0
- package/skills/review/references/ultrathink-phases.md +98 -0
- package/skills/review/references/wfs.md +6 -0
- package/skills/review/scripts/emit-review-trailer.sh +499 -0
- package/skills/review/scripts/ensure-semgrep.sh +99 -0
- package/skills/review/scripts/fix-round-seats.sh +197 -0
- package/skills/review/test/emit-review-trailer.test.sh +387 -0
- package/skills/review/test/ensure-semgrep.test.sh +111 -0
- package/skills/review/test/fix-round-seats.test.sh +237 -0
- package/skills/review/workflows/README.md +147 -0
- package/skills/review/workflows/review.workflow.js +667 -0
- package/skills/schedule/SKILL.md +796 -0
- package/skills/seo-aeo/SKILL.md +139 -0
- package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
- package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
- package/skills/ship/SKILL.md +3023 -0
- package/skills/ship/references/adr-ordinal-collision.md +47 -0
- package/skills/ship/references/affected-gate-contract.md +115 -0
- package/skills/ship/references/ci-run-diagnosis.md +29 -0
- package/skills/ship/references/ci-workflow-authoring.md +68 -0
- package/skills/ship/references/cleanup-merged-archival.md +39 -0
- package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
- package/skills/ship/references/cto-ruling-armed-push.md +5 -0
- package/skills/ship/references/decision-challenges-render.md +71 -0
- package/skills/ship/references/delegated-act-authoring-form.md +7 -0
- package/skills/ship/references/detached-battery-verdict.md +13 -0
- package/skills/ship/references/epic-close-sweep.md +62 -0
- package/skills/ship/references/feature-tweet-draft.md +42 -0
- package/skills/ship/references/followthrough-issue-body-template.md +47 -0
- package/skills/ship/references/followthrough-stub-template.sh +92 -0
- package/skills/ship/references/merge-queue-dequeue.md +39 -0
- package/skills/ship/references/operator-holds.md +179 -0
- package/skills/ship/references/pipeline-tally-render.md +43 -0
- package/skills/ship/references/pr-overlap.md +153 -0
- package/skills/ship/references/queue-mode.md +7 -0
- package/skills/ship/references/ready-run-wait.md +36 -0
- package/skills/ship/references/red-on-main-quarantine.md +110 -0
- package/skills/ship/references/register-update-pr-pattern.md +88 -0
- package/skills/ship/references/settle-then-admin-merge.md +130 -0
- package/skills/ship/references/supabase-column-probe.md +13 -0
- package/skills/ship/scripts/auto-close-scan.sh +76 -0
- package/skills/ship/scripts/battery-owed.sh +403 -0
- package/skills/ship/scripts/hold-gate-eval.sh +410 -0
- package/skills/ship/scripts/net-issue-flow.sh +665 -0
- package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
- package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
- package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
- package/skills/skill-creator/SKILL.md +299 -0
- package/skills/skill-creator/references/api-security.md +248 -0
- package/skills/skill-creator/references/authoring-levers.md +110 -0
- package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
- package/skills/skill-creator/references/best-practices.md +431 -0
- package/skills/skill-creator/references/common-patterns.md +639 -0
- package/skills/skill-creator/references/core-principles.md +193 -0
- package/skills/skill-creator/references/executable-code.md +188 -0
- package/skills/skill-creator/references/iteration-and-testing.md +509 -0
- package/skills/skill-creator/references/official-spec.md +193 -0
- package/skills/skill-creator/references/recommended-structure.md +180 -0
- package/skills/skill-creator/references/skill-structure.md +396 -0
- package/skills/skill-creator/references/using-scripts.md +122 -0
- package/skills/skill-creator/references/using-templates.md +120 -0
- package/skills/skill-creator/references/workflows-and-validation.md +541 -0
- package/skills/skill-creator/scripts/init_skill.py +322 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +64 -0
- package/skills/skill-creator/templates/router-skill.md +73 -0
- package/skills/skill-creator/templates/simple-skill.md +34 -0
- package/skills/skill-creator/workflows/add-reference.md +96 -0
- package/skills/skill-creator/workflows/add-script.md +104 -0
- package/skills/skill-creator/workflows/add-template.md +83 -0
- package/skills/skill-creator/workflows/add-workflow.md +128 -0
- package/skills/skill-creator/workflows/audit-skill.md +159 -0
- package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
- package/skills/skill-creator/workflows/create-new-skill.md +207 -0
- package/skills/skill-creator/workflows/get-guidance.md +134 -0
- package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
- package/skills/skill-creator/workflows/verify-skill.md +226 -0
- package/skills/skill-security-scan/SKILL.md +145 -0
- package/skills/skill-security-scan/references/disclaimer.md +21 -0
- package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
- package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
- package/skills/skill-security-scan/references/override-mechanism.md +171 -0
- package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
- package/skills/skill-security-scan/references/regex-patterns.md +136 -0
- package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
- package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
- package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
- package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
- package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
- package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
- package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
- package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
- package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
- package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
- package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
- package/skills/skill-security-scan/scripts/lib.sh +197 -0
- package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
- package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
- package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
- package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
- package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
- package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
- package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
- package/skills/social-distribute/SKILL.md +485 -0
- package/skills/spec-templates/SKILL.md +274 -0
- package/skills/sync/SKILL.md +49 -0
- package/skills/test-browser/SKILL.md +464 -0
- package/skills/test-browser/references/feature-map.md +161 -0
- package/skills/test-fix-loop/SKILL.md +159 -0
- package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
- package/skills/triage/SKILL.md +402 -0
- package/skills/trigger-cron/SKILL.md +136 -0
- package/skills/trigger-cron/scripts/trigger.sh +198 -0
- package/skills/user-set-role/SKILL.md +147 -0
- package/skills/user-set-role/scripts/set-role.sh +218 -0
- package/skills/user-story-writer/SKILL.md +77 -0
- package/skills/ux-audit/SKILL.md +251 -0
- package/skills/ux-audit/references/finding.schema.json +62 -0
- package/skills/ux-audit/references/route-list.yaml +95 -0
- package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
- package/skills/ux-audit/scripts/bot-signin.ts +135 -0
- package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
- package/skills/verification-scaffold/SKILL.md +73 -0
- package/skills/verification-scaffold/references/gitleaks.toml.template +13 -0
- package/skills/verification-scaffold/references/guardrail-audit.md +156 -0
- package/skills/verification-scaffold/references/guards/block-stash-hook.sh.template +72 -0
- package/skills/verification-scaffold/references/guards/commit-on-main-hook.sh.template +82 -0
- package/skills/verification-scaffold/references/guards/orphan-test-check.sh.template +102 -0
- package/skills/verification-scaffold/references/guards/precommit-guard.sh.template +115 -0
- package/skills/verification-scaffold/references/guards/secret-scan-hook.sh.template +176 -0
- package/skills/verification-scaffold/references/guards/verification-gates.yml.template +49 -0
- package/skills/verification-scaffold/references/guards/wrapper-boundary.sh.template +47 -0
- package/skills/verification-scaffold/references/guards.tsv +21 -0
- package/skills/verification-scaffold/references/verification-readme.template +55 -0
- package/skills/verification-scaffold/scripts/verification-scaffold.sh +785 -0
- package/skills/verification-scaffold/test/bite-proof.test.sh +159 -0
- package/skills/verification-scaffold/test/generator.test.sh +319 -0
- package/skills/verification-scaffold/test/manifest.test.sh +144 -0
- package/skills/work/SKILL.md +1480 -0
- package/skills/work/references/end-of-work-resume.md +7 -0
- package/skills/work/references/hook-test-main-cwd.md +24 -0
- package/skills/work/references/key-principles.md +83 -0
- package/skills/work/references/property-testing.md +122 -0
- package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
- package/skills/work/references/work-agent-teams.md +97 -0
- package/skills/work/references/work-lifecycle-parallel.md +147 -0
- package/skills/work/references/work-lockfile-bumps.md +97 -0
- package/skills/work/references/work-scratch-sandboxes.md +212 -0
- package/skills/work/references/work-subagent-fanout.md +61 -0
- package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
- package/skills/xcode-test/SKILL.md +360 -0
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soleur/opencode",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "3.354.2",
|
|
4
|
+
"description": "Soleur AI organization plugin for OpenCode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"soleur-opencode": "bin/soleur-opencode.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"install.js",
|
|
11
|
+
"bin",
|
|
12
|
+
"opencode",
|
|
13
|
+
"skills",
|
|
14
|
+
"agents",
|
|
15
|
+
"commands",
|
|
16
|
+
"scripts",
|
|
17
|
+
"hooks",
|
|
18
|
+
"lib",
|
|
19
|
+
".claude-plugin"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"yaml": "^2.8.3"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"opencode",
|
|
26
|
+
"plugin",
|
|
27
|
+
"ai-agents",
|
|
28
|
+
"soleur"
|
|
29
|
+
],
|
|
30
|
+
"author": "Jean Deruelle <jean.deruelle@jikigai.com>",
|
|
31
|
+
"license": "BUSL-1.1",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/jikig-ai/soleur.git",
|
|
35
|
+
"directory": "packages/opencode-plugin"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://soleur.ai"
|
|
38
|
+
}
|
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# admin-merge-ready.sh <PR> <head-sha> [--base BRANCH] [--wait [--timeout SEC]]
|
|
3
|
+
# admin-merge-ready.sh --help
|
|
4
|
+
#
|
|
5
|
+
# The ONLY permitted answer to "may this PR be admin-merged?" (#8500).
|
|
6
|
+
#
|
|
7
|
+
# WHY THIS EXISTS. An `--admin` merge bypasses the WHOLE `required_status_checks` ruleset
|
|
8
|
+
# rule (every required context, not just the up-to-date gate), so nothing server-side stops a
|
|
9
|
+
# red, pending or ABSENT merge. #8458 and #8439 were admin-merged that way. The obvious agent
|
|
10
|
+
# loop -- `gh pr checks --required` until nothing is pending -- lists only checks that EXIST: the
|
|
11
|
+
# aggregate `test` context is created only after every shard finishes, so it was absent (not
|
|
12
|
+
# pending) and the loop saw 25 of 26 required contexts green and merged. This script iterates
|
|
13
|
+
# the REQUIRED SET, never the present checks, so an uncreated required context reads ABSENT.
|
|
14
|
+
#
|
|
15
|
+
# HOW IT DECIDES.
|
|
16
|
+
# * The PR must be OPEN, its head must equal <head-sha>, and its base must equal --base
|
|
17
|
+
# (default `main`), re-checked on every poll. Callers merge with --match-head-commit.
|
|
18
|
+
# * Required set: `gh api repos/{owner}/{repo}/rules/branches/<base>` -- the UNION over every
|
|
19
|
+
# `required_status_checks` rule (today two rulesets: CI Required + CLA Required), deduped.
|
|
20
|
+
# An empty set is an ERROR, never "nothing required" -- that is the vacuous state. A rule
|
|
21
|
+
# type this script does not evaluate (e.g. `workflows`, `code_scanning`, `pull_request`,
|
|
22
|
+
# `required_deployments`) is also an ERROR: `--admin` bypasses it too, so ignoring it would
|
|
23
|
+
# be a silent pass. `merge_queue` (adopted #9454) is a KNOWN type that adds NO required
|
|
24
|
+
# context: it only re-runs the required set on a `merge_group` temp ref, so the required
|
|
25
|
+
# contexts it gates are exactly the ones read above. `--admin` skips the queue the same way it
|
|
26
|
+
# skips the required-status-checks rule (bypass_actors, mode pull_request; the adoption canary
|
|
27
|
+
# verifies it), and the readiness decision below is unchanged. Every OTHER unlisted type
|
|
28
|
+
# still errors.
|
|
29
|
+
# * Every required entry must be pinned to an app (`integration_id`). An unpinned entry could
|
|
30
|
+
# be satisfied by a legacy commit STATUS, which this script does not read; it is refused.
|
|
31
|
+
# * Check runs: `commits/<sha>/check-runs?filter=all`, paginated, restricted to
|
|
32
|
+
# `head_sha == <sha>`, matched by name AND `app.id == integration_id` (a run named like a
|
|
33
|
+
# context but posted by a different app, e.g. a github-actions run named for a GHAS-bound
|
|
34
|
+
# context, does not satisfy it).
|
|
35
|
+
# * Latest run per context = max check-run `id`, compared numerically. NOT `started_at`: a
|
|
36
|
+
# queued re-run has `started_at: null` and would sort as the OLDEST, letting a stale
|
|
37
|
+
# success mask a pending re-run. This mirrors GitHub, which uses the latest run per name+app.
|
|
38
|
+
# * Green = completed + success|skipped|neutral. GitHub docs, "About protected branches":
|
|
39
|
+
# "Required status checks must have a `successful`, `skipped`, or `neutral` status before
|
|
40
|
+
# collaborators can make changes to a protected branch." Do not "fix" skipped into a failure.
|
|
41
|
+
# * EXCEPT a skipped/neutral required context is only as good as its check suite: GitHub marks a
|
|
42
|
+
# job skipped when a `needs:` dependency failed and it lacks `if: always()`. If any other run
|
|
43
|
+
# in the same check suite (latest per name+app) concluded non-green, the context is FAILED
|
|
44
|
+
# (skipped-after-failure); if any is still running (a dependency being re-run), it is PENDING
|
|
45
|
+
# (skipped-while-suite-running). `--admin` is the only check, so this is stricter than
|
|
46
|
+
# GitHub on purpose: an unrelated failed job in the same workflow run also blocks.
|
|
47
|
+
# * Untrusted CI: if the PR edits `.github/workflows/` or `.github/actions/` (current or
|
|
48
|
+
# previous path of any file), its own runs could mint a genuine github-actions run under any
|
|
49
|
+
# required name, so it cannot certify itself: UNTRUSTED-CI, not-ready. Such a PR has no
|
|
50
|
+
# agent admin-merge path; the operator merges it by hand. The file list must be complete
|
|
51
|
+
# (its length must equal the PR's `changedFiles`, and the API caps at 3000), else ERROR.
|
|
52
|
+
# * Ready is decided POSITIVELY: every required context must be counted green. "No non-green
|
|
53
|
+
# line was printed" is not readiness -- an empty or unparseable API body would satisfy it.
|
|
54
|
+
#
|
|
55
|
+
# * The draft-era `test` row (ADR-276 S3, #9728). With CI_DRAFT_LIGHT on, a draft PR's `test` concludes red BY DESIGN,
|
|
56
|
+
# and after `gh pr ready` that row is the latest `test` row until the ready run's aggregator posts (38 to 51 minutes).
|
|
57
|
+
# Only when `test` is FAILED at the graded head does this script ask plugins/soleur/scripts/ci-head-verdict.sh, and the
|
|
58
|
+
# answer can only move `test` from FAILED to PENDING or ABSENT, never to green: pending-full and no-run -> PENDING (a
|
|
59
|
+
# `--wait` keeps waiting; no-run times out, never READY); stalled -> ABSENT, reason=stalled (terminal); awaiting-approval
|
|
60
|
+
# -> PENDING, reason=awaiting-approval (terminal); full-decided whose deciding run is not the run the newest `test` row
|
|
61
|
+
# belongs to (a manual re-run of a pre-ready run) -> FAILED, reason=stale-row (terminal); every other answer, an
|
|
62
|
+
# unreadable one, and a verdict for another head leave FAILED untouched. The recovery for stalled / stale-row is
|
|
63
|
+
# `gh pr ready --undo <PR>` then `gh pr ready <PR>` with a user token, never a re-run of the draft run.
|
|
64
|
+
#
|
|
65
|
+
# KNOWN LIMITS (stated, not silent).
|
|
66
|
+
# (a) A re-run started between this script's read and `gh pr merge` is not seen:
|
|
67
|
+
# `--match-head-commit` pins the head, not the checks. settle-then-admin-merge.md's merge
|
|
68
|
+
# block re-runs this script immediately before every merge attempt.
|
|
69
|
+
# (b) A check run created through the API (POST /check-runs) by any workflow token holding
|
|
70
|
+
# `checks: write` carries app 15368 and any name it likes -- including a workflow pushed to
|
|
71
|
+
# a side branch by an actor with write access. GitHub's own server-side check has the same
|
|
72
|
+
# weakness; UNTRUSTED-CI covers only workflows this PR itself edits.
|
|
73
|
+
# (c) If two workflows ever emit a job with the same required name, the newer run wins, as it
|
|
74
|
+
# does on GitHub. Probed 2026-09-22: no required name spans two check suites.
|
|
75
|
+
# (d) Classic branch protection is not read; this repo has none (`branches/main/protection`
|
|
76
|
+
# is 404) and its required checks live in rulesets (infra/github/*.tf).
|
|
77
|
+
#
|
|
78
|
+
# --green-sha <prior-sha> (was-green carryover).
|
|
79
|
+
# For a PR that is BEHIND after a green head: the operator authorizes --admin, the branch is
|
|
80
|
+
# updated (gh pr update-branch or equivalent), and the NEW head's checks have not settled.
|
|
81
|
+
# The certification is carried from <prior-sha> to <sha> only when the move between them is
|
|
82
|
+
# provably contentless:
|
|
83
|
+
# * <sha> is a 2-parent commit with .commit.verification.verified == true. Only GitHub can
|
|
84
|
+
# produce such a commit (update-branch / merge-upstream / web merge); a server-side merge
|
|
85
|
+
# cannot smuggle authored edits -- it fails on conflict instead of producing one.
|
|
86
|
+
# * parents[0] == <prior-sha>: the first parent is the head that was green.
|
|
87
|
+
# * compare(parents[1]...<base>) is ahead|identical: the second parent is an ancestor-or-
|
|
88
|
+
# equal of the base tip, so every byte the merge added came from <base>.
|
|
89
|
+
# Any failure of those three is not-ready (reason=green-carryover-*), NOT an error: the
|
|
90
|
+
# caller falls back to waiting for the new head's own checks. When the proof holds, the
|
|
91
|
+
# required-check gate runs against <prior-sha>'s check runs (which still exist -- check runs
|
|
92
|
+
# are keyed to the commit, not the branch) and the merge itself still uses
|
|
93
|
+
# --match-head-commit <sha>. UNTRUSTED-CI still refuses first: a workflow-editing PR cannot
|
|
94
|
+
# self-certify on ANY sha.
|
|
95
|
+
#
|
|
96
|
+
# --allow-local-merge (requires --green-sha; #9401).
|
|
97
|
+
# A SECOND carryover arm for a head that is NOT GitHub-signed -- a hand-made
|
|
98
|
+
# `git merge origin/<base>` push, which arrives unsigned (carryover-unverified under the
|
|
99
|
+
# arm above). (The #9401 disjoint-delta skip needs NO carryover: it leaves the green head
|
|
100
|
+
# untouched, so a plain invocation grades it directly; and a hook-produced sync merge can
|
|
101
|
+
# never satisfy this arm -- its delta overlaps the PR's files by construction.) The
|
|
102
|
+
# signature is replaced by
|
|
103
|
+
# a mechanical proof that the merge added nothing but base-side docs content:
|
|
104
|
+
# * still a 2-parent commit with parents[0] == <green-sha> -- a non-merge or a merge of a
|
|
105
|
+
# different head is refused as carryover-not-merge / carryover-first-parent, flag or not;
|
|
106
|
+
# * parents[1] is an ancestor-or-equal of <base> (same compare as the verified arm);
|
|
107
|
+
# * compare(<green-sha>...<sha>)'s file list EQUALS
|
|
108
|
+
# compare(<green-sha>...parents[1])'s as a set of (filename, status, previous_filename,
|
|
109
|
+
# patch) tuples -- a merge that resolved a conflict or authored an edit diverges from
|
|
110
|
+
# the base-side patch, a file it added beyond the base delta is smuggled, and a file it
|
|
111
|
+
# DROPPED (a subset-only check would certify a merge that reverts base content -- e.g.
|
|
112
|
+
# parents [G, tip] with G's tree) fails the equality;
|
|
113
|
+
# * every such file sits on the docs surface (knowledge-base/, docs/,
|
|
114
|
+
# plugins/soleur/skills/, or *.md) -- base-side CODE carried by an unsigned merge is not
|
|
115
|
+
# certifiable by a gate that cannot replay it;
|
|
116
|
+
# * none of them appear in the PR's own file list -- an overlap means merge-time
|
|
117
|
+
# resolution touched content the PR owns.
|
|
118
|
+
# Success grades <green-sha>'s contexts and reports reason=carryover-local-docs. Refusals
|
|
119
|
+
# are not-ready (carryover-local-not-clean / -nondocs / -overlap), never errors; a truncated
|
|
120
|
+
# (>=300-entry) or unparseable compare body is an error, like every other unreadable input.
|
|
121
|
+
#
|
|
122
|
+
# EXIT CODES (the contract every caller branches on).
|
|
123
|
+
# 0 ready every required context present and green on this head -> merge with
|
|
124
|
+
# --match-head-commit <sha>
|
|
125
|
+
# 1 not-ready something ABSENT/PENDING/FAILED (--wait: a FAILED is terminal), UNTRUSTED-CI,
|
|
126
|
+
# base mismatch, or --wait timeout (verdict=timeout) -> stop, never merge
|
|
127
|
+
# 2 error usage
|
|
128
|
+
# 3 error gh/jq missing, any API failure or unparseable body, empty required set,
|
|
129
|
+
# unpinned context, unsupported rule type, incomplete file list
|
|
130
|
+
# 4 stale PR not OPEN, or head moved off <sha> -> re-read the SHA and restart
|
|
131
|
+
# 130 interrupted (signal); marker verdict=error
|
|
132
|
+
# Every path except --help prints the marker as its LAST stdout line:
|
|
133
|
+
# SOLEUR_ADMIN_MERGE_READY verdict=<ready|not-ready|stale|timeout|error> pr=<N> sha=<sha>
|
|
134
|
+
# base=<branch> reason=<token> required=<n> absent=<json> pending=<json> failed=<json>
|
|
135
|
+
# Name arrays are compact JSON because context names contain spaces, parentheses, '#' and ':'.
|
|
136
|
+
# PR-controlled strings (file paths) are never printed.
|
|
137
|
+
#
|
|
138
|
+
# --wait polls every ADMIN_MERGE_READY_POLL_SECONDS (default 60; test seam, must be ^[0-9]+$).
|
|
139
|
+
# The budget is counted in 60-second POLLS (ceil(timeout/60)), so a 0-second test poll gives the
|
|
140
|
+
# same poll count as production. Emits one WAIT line when the non-green set changes, a HEARTBEAT
|
|
141
|
+
# every 5 unchanged polls, and exactly one marker at the end. Host it in the Monitor tool.
|
|
142
|
+
set -uo pipefail
|
|
143
|
+
|
|
144
|
+
readonly MARKER="SOLEUR_ADMIN_MERGE_READY"
|
|
145
|
+
|
|
146
|
+
usage() {
|
|
147
|
+
cat <<'EOF'
|
|
148
|
+
usage: admin-merge-ready.sh <PR> <head-sha> [--base BRANCH] [--wait [--timeout SEC]]
|
|
149
|
+
admin-merge-ready.sh <PR> <head-sha> --green-sha <prior-sha> [--allow-local-merge] [--base BRANCH]
|
|
150
|
+
admin-merge-ready.sh --help
|
|
151
|
+
|
|
152
|
+
Exits 0 only when every context required by the base branch's rulesets is PRESENT on
|
|
153
|
+
<head-sha> and its latest check run concluded success|skipped|neutral.
|
|
154
|
+
With --green-sha the gate runs against <prior-sha> instead: valid only when <head-sha>
|
|
155
|
+
is GitHub's own verified 2-parent merge of <prior-sha> and an ancestor-or-equal of the
|
|
156
|
+
base tip (was-green carryover; see the header). With --allow-local-merge an unsigned
|
|
157
|
+
local merge is also certified, but only when the delta it added over <prior-sha> is a
|
|
158
|
+
byte-identical replay of the base-side delta, docs-only, and disjoint from the PR's
|
|
159
|
+
own file list.
|
|
160
|
+
|
|
161
|
+
exit 0 ready | 1 not-ready|timeout | 2 usage error | 3 gh/jq/API/ruleset error | 4 stale (head moved / PR not open)
|
|
162
|
+
|
|
163
|
+
Last stdout line, on every path except --help:
|
|
164
|
+
SOLEUR_ADMIN_MERGE_READY verdict=<ready|not-ready|stale|timeout|error> pr=<N> sha=<sha> base=<branch> reason=<token> required=<n> absent=<json-array> pending=<json-array> failed=<json-array>
|
|
165
|
+
EOF
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
PR_OUT="?"; SHA_OUT="?"; BASE="?"; REASON="none"; REASON_OVERRIDE=""
|
|
169
|
+
N_REQ=0; J_ABSENT="[]"; J_PENDING="[]"; J_FAILED="[]"
|
|
170
|
+
|
|
171
|
+
marker() {
|
|
172
|
+
printf '%s verdict=%s pr=%s sha=%s base=%s reason=%s required=%s absent=%s pending=%s failed=%s\n' \
|
|
173
|
+
"$MARKER" "$1" "$PR_OUT" "$SHA_OUT" "$BASE" "$REASON" "$N_REQ" "$J_ABSENT" "$J_PENDING" "$J_FAILED"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
usage_error() {
|
|
177
|
+
echo "admin-merge-ready: $1" >&2
|
|
178
|
+
usage >&2
|
|
179
|
+
REASON=usage
|
|
180
|
+
marker error
|
|
181
|
+
exit 2
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
# ── args ──────────────────────────────────────────────────────────────────────────────────────
|
|
185
|
+
if [[ "${1-}" == "--help" || "${1-}" == "-h" ]]; then usage; exit 0; fi
|
|
186
|
+
PR="${1-}"; SHA="${2-}"
|
|
187
|
+
[[ "$PR" =~ ^[0-9]+$ ]] || usage_error "PR must be a number"
|
|
188
|
+
PR_OUT="$PR"
|
|
189
|
+
[[ "$SHA" =~ ^[0-9a-f]{40}$ ]] || usage_error "head-sha must be a full 40-hex SHA"
|
|
190
|
+
SHA_OUT="$SHA"
|
|
191
|
+
shift 2
|
|
192
|
+
WAIT=0; TIMEOUT=3600; WANT_BASE="main"; GREEN_SHA=""; ALLOW_LOCAL=0
|
|
193
|
+
while (( $# > 0 )); do
|
|
194
|
+
case "$1" in
|
|
195
|
+
--wait) WAIT=1; shift ;;
|
|
196
|
+
--timeout)
|
|
197
|
+
if ! [[ "${2-}" =~ ^[0-9]+$ ]] || (( 10#$2 == 0 )); then usage_error "--timeout must be a positive integer"; fi
|
|
198
|
+
TIMEOUT=$((10#$2)); shift 2 ;;
|
|
199
|
+
--base)
|
|
200
|
+
if ! [[ "${2-}" =~ ^[A-Za-z0-9._/-]+$ ]]; then usage_error "--base must be a branch name"; fi
|
|
201
|
+
WANT_BASE="$2"; shift 2 ;;
|
|
202
|
+
--green-sha)
|
|
203
|
+
if ! [[ "${2-}" =~ ^[0-9a-f]{40}$ ]]; then usage_error "--green-sha must be a full 40-hex SHA"; fi
|
|
204
|
+
GREEN_SHA="$2"; shift 2 ;;
|
|
205
|
+
--allow-local-merge) ALLOW_LOCAL=1; shift ;;
|
|
206
|
+
*) usage_error "unknown argument" ;;
|
|
207
|
+
esac
|
|
208
|
+
done
|
|
209
|
+
[[ -z "$GREEN_SHA" || "$GREEN_SHA" != "$SHA" ]] \
|
|
210
|
+
|| usage_error "--green-sha equals <head-sha> -- plain invocation already covers it"
|
|
211
|
+
[[ "$ALLOW_LOCAL" != "1" || -n "$GREEN_SHA" ]] \
|
|
212
|
+
|| usage_error "--allow-local-merge requires --green-sha"
|
|
213
|
+
POLL_SECONDS="${ADMIN_MERGE_READY_POLL_SECONDS:-60}"
|
|
214
|
+
[[ "$POLL_SECONDS" =~ ^[0-9]+$ ]] || usage_error "ADMIN_MERGE_READY_POLL_SECONDS must be ^[0-9]+\$"
|
|
215
|
+
|
|
216
|
+
for bin in gh jq; do
|
|
217
|
+
command -v "$bin" >/dev/null 2>&1 || { echo "ERROR: $bin not found on PATH" >&2; REASON="missing-tool"; marker error; exit 3; }
|
|
218
|
+
done
|
|
219
|
+
|
|
220
|
+
WORK="$(mktemp -d)" || { echo "ERROR: mktemp failed" >&2; REASON=mktemp; marker error; exit 3; }
|
|
221
|
+
trap 'rm -rf "$WORK"' EXIT
|
|
222
|
+
trap 'REASON=interrupted; marker error; exit 130' INT TERM HUP
|
|
223
|
+
|
|
224
|
+
# ── one readiness read ───────────────────────────────────────────────────────────────────────
|
|
225
|
+
# Sets LINES (newline-joined non-green lines), N_REQ, J_ABSENT/J_PENDING/J_FAILED, MSG, REASON.
|
|
226
|
+
# Returns 0 ready | 1 not-ready | 4 stale | 3 error.
|
|
227
|
+
fail3() { MSG="ERROR: $1"; REASON="$2"; return 3; }
|
|
228
|
+
|
|
229
|
+
# resolve_head_verdict: V_STATE / V_RUN from ci-head-verdict.sh for THIS PR at THIS head ($SHA). Returns 1 (and leaves
|
|
230
|
+
# V_STATE empty) when it cannot answer: the caller then keeps today's reading. CI_HEAD_VERDICT_BIN is the test seam.
|
|
231
|
+
V_STATE=""; V_RUN="none"; V_WHY=""
|
|
232
|
+
resolve_head_verdict() {
|
|
233
|
+
local bin m
|
|
234
|
+
V_STATE=""; V_RUN="none"; V_WHY=""
|
|
235
|
+
bin="${CI_HEAD_VERDICT_BIN:-$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)/ci-head-verdict.sh}"
|
|
236
|
+
[[ -r "$bin" ]] || return 1
|
|
237
|
+
m="$(bash "$bin" verdict "$PR" 2>/dev/null)" || true
|
|
238
|
+
m="$(grep -m1 '^SOLEUR_CI_HEAD_VERDICT ' <<<"$m")" || return 1
|
|
239
|
+
[[ "$m" == *" sha=$SHA "* ]] || return 1
|
|
240
|
+
V_RUN="${m#* run=}"; V_RUN="${V_RUN%% *}"; V_WHY="${m#* reason=}"; V_WHY="${V_WHY%% *}"
|
|
241
|
+
m="${m#*state=}"; m="${m%% *}"
|
|
242
|
+
case "$m" in n/a|full-decided|pending-full|no-run|stalled|awaiting-approval) V_STATE="$m" ;; *) return 1 ;; esac
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
# soften_test_row <classifier-json>: apply the head verdict to a FAILED `test` (see the header). Prints the adjusted JSON;
|
|
246
|
+
# sets REASON_OVERRIDE and MSG when the answer is terminal. Never produces a green context.
|
|
247
|
+
RECOVERY=""
|
|
248
|
+
soften_test_row() {
|
|
249
|
+
local out="$1" last_run=""
|
|
250
|
+
RECOVERY="after confirming in the Actions tab that no ready run is still in flight (the undo cancels it): gh pr ready --undo $PR, then gh pr ready $PR with a user token (never GITHUB_TOKEN; a manual re-run of the draft run is NOT a recovery)"
|
|
251
|
+
case "$V_STATE" in
|
|
252
|
+
pending-full)
|
|
253
|
+
jq -c '.failed -= ["test"] | .pending += ["test"]
|
|
254
|
+
| .lines |= map(if startswith("FAILED test (") then "PENDING test (draft-era-row-while-ready-run-pending)" else . end)' <<<"$out" > "$WORK/soft.json" ;;
|
|
255
|
+
no-run)
|
|
256
|
+
jq -c '.failed -= ["test"] | .pending += ["test"]
|
|
257
|
+
| .lines |= map(if startswith("FAILED test (") then "PENDING test (no-ready-run)" else . end)' <<<"$out" > "$WORK/soft.json" ;;
|
|
258
|
+
awaiting-approval)
|
|
259
|
+
REASON_OVERRIDE="awaiting-approval"
|
|
260
|
+
MSG="AWAITING-APPROVAL: the ready run is waiting for a maintainer to approve a fork workflow run; nothing starts until it is approved"
|
|
261
|
+
jq -c '.failed -= ["test"] | .pending += ["test"]
|
|
262
|
+
| .lines |= map(if startswith("FAILED test (") then "PENDING test (awaiting-approval: a maintainer must approve the fork workflow run)" else . end)' <<<"$out" > "$WORK/soft.json" ;;
|
|
263
|
+
stalled)
|
|
264
|
+
REASON_OVERRIDE="stalled"
|
|
265
|
+
MSG="STALLED: this PR was marked ready but no full CI run decided ($V_WHY: see ci-head-verdict.sh --help for the stall clock). Recovery: $RECOVERY"
|
|
266
|
+
jq -c '.failed -= ["test"] | .absent += ["test"]
|
|
267
|
+
| .lines |= map(if startswith("FAILED test (") then "ABSENT test (stalled: no full CI run decided after the ready event)" else . end)' <<<"$out" > "$WORK/soft.json" ;;
|
|
268
|
+
full-decided)
|
|
269
|
+
last_run="$(jq -r --arg sha "$CHECK_SHA" '
|
|
270
|
+
[.[] | .check_runs[] | select(.head_sha == $sha and .name == "test" and .app.id == 15368)]
|
|
271
|
+
| if length == 0 then "" else (max_by(.id | tonumber) | (.details_url // "") | (capture("/actions/runs/(?<id>[0-9]+)(/|$)")? // {id: ""}) | .id) end' "$WORK/runs.json" 2>/dev/null)" || last_run=""
|
|
272
|
+
if [[ -n "$last_run" && "$V_RUN" != none && "$last_run" != "$V_RUN" ]]; then
|
|
273
|
+
REASON_OVERRIDE="stale-row"
|
|
274
|
+
MSG="STALE-ROW: the newest test row belongs to run $last_run, not the deciding run $V_RUN (a manual re-run of a pre-ready run). Recovery: $RECOVERY"
|
|
275
|
+
jq -c --arg l "$last_run" --arg r "$V_RUN" \
|
|
276
|
+
'.lines |= map(if startswith("FAILED test (") then "FAILED test (stale-row: the newest test row belongs to run \($l), not the deciding run \($r))" else . end)' <<<"$out" > "$WORK/soft.json"
|
|
277
|
+
else
|
|
278
|
+
printf '%s\n' "$out" > "$WORK/soft.json"
|
|
279
|
+
fi ;;
|
|
280
|
+
*) printf '%s\n' "$out" > "$WORK/soft.json" ;;
|
|
281
|
+
esac
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
check_once() {
|
|
285
|
+
LINES=""; MSG=""; REASON="none"; REASON_OVERRIDE=""; N_REQ=0; J_ABSENT="[]"; J_PENDING="[]"; J_FAILED="[]"
|
|
286
|
+
rm -f "$WORK"/*.json
|
|
287
|
+
local state head changed enc
|
|
288
|
+
|
|
289
|
+
gh pr view "$PR" --json state,headRefOid,baseRefName,changedFiles > "$WORK/pr.json" \
|
|
290
|
+
|| { fail3 "gh pr view $PR failed" api-error; return; }
|
|
291
|
+
jq -e 'type == "object" and (.state|type) == "string" and (.headRefOid|type) == "string"
|
|
292
|
+
and (.baseRefName|type) == "string" and (.changedFiles|type) == "number"' "$WORK/pr.json" >/dev/null 2>&1 \
|
|
293
|
+
|| { fail3 "unparseable gh pr view output" api-error; return; }
|
|
294
|
+
state=$(jq -r '.state' "$WORK/pr.json")
|
|
295
|
+
head=$(jq -r '.headRefOid' "$WORK/pr.json")
|
|
296
|
+
changed=$(jq -r '.changedFiles' "$WORK/pr.json")
|
|
297
|
+
BASE=$(jq -r '.baseRefName' "$WORK/pr.json")
|
|
298
|
+
[[ "$BASE" =~ ^[A-Za-z0-9._/-]+$ ]] || { BASE="?"; fail3 "PR base branch unreadable" api-error; return; }
|
|
299
|
+
if [[ "$state" != "OPEN" ]]; then MSG="NOT-OPEN: PR is not open"; REASON="not-open"; return 4; fi
|
|
300
|
+
if [[ "$head" != "$SHA" ]]; then MSG="STALE: the PR head moved off $SHA"; REASON="head-moved"; return 4; fi
|
|
301
|
+
if [[ "$BASE" != "$WANT_BASE" ]]; then
|
|
302
|
+
MSG="BASE-MISMATCH: the PR targets $BASE, not $WANT_BASE"; REASON="base-mismatch"; return 1
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
gh api --paginate --slurp "repos/{owner}/{repo}/pulls/$PR/files?per_page=100" > "$WORK/files.json" \
|
|
306
|
+
|| { fail3 "reading PR files failed" api-error; return; }
|
|
307
|
+
local nfiles nci
|
|
308
|
+
nfiles=$(jq -e 'if type == "array" and all(.[]; type == "array") then [.[][]] | length else error("shape") end' \
|
|
309
|
+
"$WORK/files.json" 2>/dev/null) || { fail3 "unparseable PR file list" api-error; return; }
|
|
310
|
+
if (( changed >= 3000 || nfiles != changed )); then
|
|
311
|
+
fail3 "PR file list incomplete ($nfiles listed, $changed changed; the API caps at 3000)" incomplete-files; return
|
|
312
|
+
fi
|
|
313
|
+
nci=$(jq -r '[.[][] | [.filename, (.previous_filename // "")][]
|
|
314
|
+
| select(test("^\\.github/(workflows|actions)/"))] | length' "$WORK/files.json") \
|
|
315
|
+
|| { fail3 "unparseable PR file list" api-error; return; }
|
|
316
|
+
if (( nci > 0 )); then
|
|
317
|
+
MSG="UNTRUSTED-CI: this PR edits $nci workflow-definition path(s) under .github/, so its own check runs cannot certify it"
|
|
318
|
+
REASON="untrusted-ci"; return 1
|
|
319
|
+
fi
|
|
320
|
+
|
|
321
|
+
# --green-sha carryover: prove <sha> is GitHub's own contentless merge of the certified
|
|
322
|
+
# <green-sha> and the base branch, then grade <green-sha>'s check runs. Verified merges are
|
|
323
|
+
# server-side only (GitHub signs them; a server merge fails on conflict rather than
|
|
324
|
+
# absorbing edits), so verified+2-parents+parents[0]==green+parents[1] an ancestor-or-equal
|
|
325
|
+
# of <base> means the delta is exactly base content.
|
|
326
|
+
CHECK_SHA="$SHA"
|
|
327
|
+
if [[ -n "$GREEN_SHA" ]]; then
|
|
328
|
+
gh api "repos/{owner}/{repo}/commits/$SHA" > "$WORK/head.json" \
|
|
329
|
+
|| { fail3 "reading head commit failed" api-error; return; }
|
|
330
|
+
local carry p1 cstatus
|
|
331
|
+
carry=$(jq -r --arg green "$GREEN_SHA" '
|
|
332
|
+
(.commit.verification.verified // false) as $v
|
|
333
|
+
| (.parents // []) as $p
|
|
334
|
+
| if ($p | length) != 2 then "carryover-not-merge"
|
|
335
|
+
elif $p[0].sha != $green then "carryover-first-parent"
|
|
336
|
+
elif $v != true then "carryover-unverified"
|
|
337
|
+
else "ok " + $p[1].sha end' "$WORK/head.json" 2>/dev/null) \
|
|
338
|
+
|| { fail3 "unparseable head commit" api-error; return; }
|
|
339
|
+
# Only carryover-unverified is eligible for the local-merge arm: a head that
|
|
340
|
+
# is not a merge, or whose first parent is not <green-sha>, is the wrong
|
|
341
|
+
# SHAPE for carryover and refused the same with or without the flag.
|
|
342
|
+
if [[ "$carry" == ok\ * ]]; then
|
|
343
|
+
p1="${carry#ok }"
|
|
344
|
+
elif [[ "$carry" == "carryover-unverified" && "$ALLOW_LOCAL" == "1" ]]; then
|
|
345
|
+
p1=$(jq -r '.parents[1].sha // ""' "$WORK/head.json" 2>/dev/null) || p1=""
|
|
346
|
+
[[ "$p1" =~ ^[0-9a-f]{40}$ ]] || { fail3 "unparseable head commit" api-error; return; }
|
|
347
|
+
else
|
|
348
|
+
MSG="GREEN-CARRYOVER refused: head $SHA is not a verified GitHub merge of $GREEN_SHA ($carry)"
|
|
349
|
+
REASON="$carry"; return 1
|
|
350
|
+
fi
|
|
351
|
+
gh api "repos/{owner}/{repo}/compare/$p1...$BASE" > "$WORK/compare.json" \
|
|
352
|
+
|| { fail3 "compare of merged parent against $BASE failed" api-error; return; }
|
|
353
|
+
cstatus=$(jq -r '.status // ""' "$WORK/compare.json" 2>/dev/null) \
|
|
354
|
+
|| { fail3 "unparseable compare response" api-error; return; }
|
|
355
|
+
if [[ "$cstatus" != "ahead" && "$cstatus" != "identical" ]]; then
|
|
356
|
+
MSG="GREEN-CARRYOVER refused: merged parent $p1 is not an ancestor-or-equal of $BASE (status=$cstatus)"
|
|
357
|
+
REASON="carryover-not-base"; return 1
|
|
358
|
+
fi
|
|
359
|
+
if [[ "$carry" == ok\ * ]]; then
|
|
360
|
+
CHECK_SHA="$GREEN_SHA"
|
|
361
|
+
MSG="GREEN-CARRYOVER: head $SHA is a verified merge of $GREEN_SHA and $BASE@$p1; grading $GREEN_SHA's required contexts"
|
|
362
|
+
else
|
|
363
|
+
# --allow-local-merge arm (#9401): the signature is replaced by a diff
|
|
364
|
+
# proof -- every file the merge added over <green-sha> must be a byte-
|
|
365
|
+
# identical replay of the base-side delta, docs-only, and disjoint from
|
|
366
|
+
# the PR's own file list.
|
|
367
|
+
gh api "repos/{owner}/{repo}/compare/$GREEN_SHA...$SHA" > "$WORK/cmp_added.json" \
|
|
368
|
+
|| { fail3 "compare of the merge's added delta failed" api-error; return; }
|
|
369
|
+
gh api "repos/{owner}/{repo}/compare/$GREEN_SHA...$p1" > "$WORK/cmp_base.json" \
|
|
370
|
+
|| { fail3 "compare of the merged base tip failed" api-error; return; }
|
|
371
|
+
local lcl
|
|
372
|
+
# One jq, one error path: clean-replay, docs-only and PR-disjointness are
|
|
373
|
+
# a single predicate so a residual jq failure can never half-evaluate.
|
|
374
|
+
lcl=$(jq -rn --slurpfile added "$WORK/cmp_added.json" --slurpfile base "$WORK/cmp_base.json" \
|
|
375
|
+
--slurpfile prf "$WORK/files.json" '
|
|
376
|
+
# docs surface: sibling enumeration of the zero-conflict-surface
|
|
377
|
+
# classifier in ship/references/settle-then-admin-merge.md — different
|
|
378
|
+
# subject (merged delta vs the PR file list) but same surface; a move
|
|
379
|
+
# of the docs roots must touch both. NO apostrophes in jq comments —
|
|
380
|
+
# this program is single-quoted.
|
|
381
|
+
def docs: .filename | test("^(knowledge-base/|docs/|plugins/soleur/skills/)") or test("\\.md$");
|
|
382
|
+
($added[0].files // null) as $af | ($base[0].files // null) as $bf
|
|
383
|
+
| ([$prf[0][][] | .filename, (.previous_filename // empty)] | unique) as $pf
|
|
384
|
+
| if $af == null or $bf == null then "error:unparseable"
|
|
385
|
+
# The compare API truncates files[] at 300 entries (docs.github.com
|
|
386
|
+
# REST compare commits) — at exactly 300 a complete list is
|
|
387
|
+
# indistinguishable from a truncated one, so fail closed.
|
|
388
|
+
elif ($af | length) >= 300 or ($bf | length) >= 300 then "error:incomplete"
|
|
389
|
+
# Bijection, not subset: a merge whose tree DROPPED base-side content
|
|
390
|
+
# (empty or partial $af) must not certify -- the admin merge would
|
|
391
|
+
# revert main. The tuple includes previous_filename so a rename source
|
|
392
|
+
# is bound, and every patch must be a real string.
|
|
393
|
+
elif any($af[] + $bf[]; (.patch | type) != "string")
|
|
394
|
+
or ([$af[] | [.filename, .status, (.previous_filename // ""), .patch]] | sort)
|
|
395
|
+
!= ([$bf[] | [.filename, .status, (.previous_filename // ""), .patch]] | sort)
|
|
396
|
+
then "not-clean"
|
|
397
|
+
elif any($af[]; docs | not) then "nondocs"
|
|
398
|
+
elif any($af[]; [.filename, (.previous_filename // empty)]
|
|
399
|
+
| .[] | . as $f | ($pf | index($f)) != null) then "overlap"
|
|
400
|
+
else "ok" end' 2>/dev/null) || { fail3 "unparseable compare response" api-error; return; }
|
|
401
|
+
if [[ "$lcl" == error:* ]]; then
|
|
402
|
+
fail3 "merge-delta compare is unparseable or truncated (${lcl#error:})" incomplete-files; return
|
|
403
|
+
fi
|
|
404
|
+
if [[ "$lcl" != "ok" ]]; then
|
|
405
|
+
MSG="GREEN-CARRYOVER refused: the local merge's added delta is not a clean docs-only replay of the base side, disjoint from the PR's files ($lcl)"
|
|
406
|
+
REASON="carryover-local-$lcl"; return 1
|
|
407
|
+
fi
|
|
408
|
+
CHECK_SHA="$GREEN_SHA"
|
|
409
|
+
REASON="carryover-local-docs"
|
|
410
|
+
MSG="GREEN-CARRYOVER: head $SHA is a clean local merge of $GREEN_SHA and $BASE@$p1 (docs-only delta, disjoint from the PR's files; --allow-local-merge); grading $GREEN_SHA's required contexts"
|
|
411
|
+
fi
|
|
412
|
+
fi
|
|
413
|
+
|
|
414
|
+
enc=$(jq -rn --arg b "$BASE" '$b|@uri')
|
|
415
|
+
gh api --paginate --slurp "repos/{owner}/{repo}/rules/branches/$enc" > "$WORK/rules.json" \
|
|
416
|
+
|| { fail3 "reading the ruleset required set failed" api-error; return; }
|
|
417
|
+
gh api --paginate --slurp "repos/{owner}/{repo}/commits/$CHECK_SHA/check-runs?per_page=100&filter=all" > "$WORK/runs.json" \
|
|
418
|
+
|| { fail3 "reading check runs failed" api-error; return; }
|
|
419
|
+
jq -e 'type == "array" and all(.[]; type == "array")' "$WORK/rules.json" >/dev/null 2>&1 \
|
|
420
|
+
|| { fail3 "unparseable ruleset response" api-error; return; }
|
|
421
|
+
jq -e 'type == "array" and all(.[]; type == "object" and (.check_runs|type) == "array")' "$WORK/runs.json" >/dev/null 2>&1 \
|
|
422
|
+
|| { fail3 "unparseable check-runs response" api-error; return; }
|
|
423
|
+
|
|
424
|
+
local out
|
|
425
|
+
out=$(jq -c --slurpfile rules "$WORK/rules.json" --arg sha "$CHECK_SHA" '
|
|
426
|
+
["deletion","non_fast_forward","creation","update","required_linear_history",
|
|
427
|
+
"required_signatures","required_status_checks","merge_queue"] as $known
|
|
428
|
+
| ($rules[0] | add // []) as $all
|
|
429
|
+
| ([$all[] | .type | select(. as $t | $known | index($t) | not)] | unique) as $unknown
|
|
430
|
+
| ([$all[] | select(.type == "required_status_checks") | .parameters.required_status_checks[]?]
|
|
431
|
+
| reduce .[] as $e ([]; if any(.[]; .context == $e.context and .integration_id == $e.integration_id)
|
|
432
|
+
then . else . + [$e] end)) as $req
|
|
433
|
+
| [.[] | .check_runs[] | select(.head_sha == $sha)] as $runs
|
|
434
|
+
| if ($unknown | length) > 0 then {error: ("unsupported ruleset rule type(s) " + ($unknown | tojson)), reason: "unsupported-rule"}
|
|
435
|
+
elif ($req | length) == 0 then {error: "required set unreadable or empty", reason: "empty-required"}
|
|
436
|
+
elif any($req[]; .integration_id == null) then
|
|
437
|
+
{error: ("unpinned required context(s) " + ([$req[] | select(.integration_id == null) | .context] | tojson) + " unsupported"), reason: "unpinned"}
|
|
438
|
+
else
|
|
439
|
+
# Latest run per (name, app, suite): the state of every job in a check suite.
|
|
440
|
+
( $runs | group_by([.name, .app.id, .check_suite.id]) | map(max_by(.id | tonumber)) ) as $latest
|
|
441
|
+
| [ $req[] as $q
|
|
442
|
+
| [ $runs[] | select(.name == $q.context and .app.id == $q.integration_id) ] as $c
|
|
443
|
+
| if ($c | length) == 0 then {k: "ABSENT", n: $q.context}
|
|
444
|
+
else ($c | max_by(.id | tonumber)) as $l
|
|
445
|
+
| if $l.status == "completed" then
|
|
446
|
+
if $l.conclusion == "success" then {k: "GREEN", n: $q.context}
|
|
447
|
+
elif ($l.conclusion == "skipped" or $l.conclusion == "neutral") then
|
|
448
|
+
( [ $latest[] | select(.check_suite.id != null and .check_suite.id == $l.check_suite.id
|
|
449
|
+
and .id != $l.id) ] ) as $sib
|
|
450
|
+
| if $l.check_suite.id == null then {k: "FAILED", n: $q.context, d: ($l.conclusion + " without a check suite")}
|
|
451
|
+
elif any($sib[]; .status == "completed"
|
|
452
|
+
and ((.conclusion // "") as $x | ["success","skipped","neutral"] | index($x) | not))
|
|
453
|
+
then {k: "FAILED", n: $q.context, d: ($l.conclusion + "-after-failure")}
|
|
454
|
+
elif any($sib[]; .status != "completed")
|
|
455
|
+
then {k: "PENDING", n: $q.context, d: ($l.conclusion + "-while-suite-running")}
|
|
456
|
+
else {k: "GREEN", n: $q.context} end
|
|
457
|
+
else {k: "FAILED", n: $q.context, d: ($l.conclusion // "null")} end
|
|
458
|
+
elif (["queued","in_progress","waiting","requested","pending"] | index($l.status)) then
|
|
459
|
+
{k: "PENDING", n: $q.context, d: $l.status}
|
|
460
|
+
else {k: "FAILED", n: $q.context, d: ("unknown status " + ($l.status | tostring))} end
|
|
461
|
+
end ] as $v
|
|
462
|
+
| { req: ($req | length),
|
|
463
|
+
green: [$v[] | select(.k == "GREEN") | .n] | length,
|
|
464
|
+
absent: [$v[] | select(.k == "ABSENT") | .n],
|
|
465
|
+
pending: [$v[] | select(.k == "PENDING") | .n],
|
|
466
|
+
failed: [$v[] | select(.k == "FAILED") | .n],
|
|
467
|
+
lines: [$v[] | select(.k != "GREEN")
|
|
468
|
+
| if .k == "ABSENT" then "ABSENT \(.n)"
|
|
469
|
+
elif .k == "PENDING" then "PENDING \(.n) (\(.d))"
|
|
470
|
+
else "FAILED \(.n) (\(.d))" end] }
|
|
471
|
+
end' "$WORK/runs.json") || { fail3 "classifying check runs failed" api-error; return; }
|
|
472
|
+
|
|
473
|
+
# Positive shape check on the classifier's own output before reading any field of it.
|
|
474
|
+
jq -e 'type == "object" and ((has("error") and (.error|type) == "string")
|
|
475
|
+
or ((.req|type) == "number" and (.green|type) == "number" and (.lines|type) == "array"))' \
|
|
476
|
+
<<<"$out" >/dev/null 2>&1 || { fail3 "classifier produced no verdict" api-error; return; }
|
|
477
|
+
if jq -e 'has("error")' <<<"$out" >/dev/null; then
|
|
478
|
+
MSG="ERROR: $(jq -r '.error' <<<"$out")"; REASON=$(jq -r '.reason' <<<"$out"); return 3
|
|
479
|
+
fi
|
|
480
|
+
# ADR-276 S3: a FAILED `test` at the graded head may be the draft run's row. Ask the resolver, only then.
|
|
481
|
+
if [[ "$CHECK_SHA" == "$SHA" ]] && jq -e '.failed | index("test") != null' <<<"$out" >/dev/null 2>&1 && resolve_head_verdict; then
|
|
482
|
+
soften_test_row "$out"; out="$(cat "$WORK/soft.json" 2>/dev/null)"
|
|
483
|
+
jq -e 'type == "object" and (.lines | type) == "array"' <<<"$out" >/dev/null 2>&1 \
|
|
484
|
+
|| { fail3 "adjusting the test verdict failed" api-error; return; }
|
|
485
|
+
fi
|
|
486
|
+
N_REQ=$(jq -r '.req' <<<"$out")
|
|
487
|
+
J_ABSENT=$(jq -c '.absent' <<<"$out")
|
|
488
|
+
J_PENDING=$(jq -c '.pending' <<<"$out")
|
|
489
|
+
J_FAILED=$(jq -c '.failed' <<<"$out")
|
|
490
|
+
LINES=$(jq -r '.lines[]' <<<"$out")
|
|
491
|
+
if jq -e '.req > 0 and .green == .req and (.lines | length) == 0' <<<"$out" >/dev/null; then
|
|
492
|
+
# A carryover arm that already named itself (carryover-local-docs) keeps its
|
|
493
|
+
# reason; a plain or verified-carryover ready reads all-green as before.
|
|
494
|
+
[[ "$REASON" == "none" ]] && REASON="all-green"
|
|
495
|
+
return 0
|
|
496
|
+
fi
|
|
497
|
+
if [[ -z "$LINES" ]]; then fail3 "classifier counted $(jq -r '.green' <<<"$out") of $N_REQ green but named no culprit" api-error; return; fi
|
|
498
|
+
REASON="${REASON_OVERRIDE:-not-green}"; return 1
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
finish() { # <rc> <verdict>
|
|
502
|
+
if [[ -n "$MSG" ]]; then
|
|
503
|
+
if [[ "$1" == 3 ]]; then printf '%s\n' "$MSG" >&2; else printf '%s\n' "$MSG"; fi
|
|
504
|
+
fi
|
|
505
|
+
[[ -n "$LINES" ]] && printf '%s\n' "$LINES"
|
|
506
|
+
marker "$2"
|
|
507
|
+
exit "$1"
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
# ── single check ─────────────────────────────────────────────────────────────────────────────
|
|
511
|
+
if (( WAIT == 0 )); then
|
|
512
|
+
check_once; rc=$?
|
|
513
|
+
case "$rc" in
|
|
514
|
+
0) finish 0 ready ;;
|
|
515
|
+
1) finish 1 not-ready ;;
|
|
516
|
+
4) finish 4 stale ;;
|
|
517
|
+
*) finish 3 error ;;
|
|
518
|
+
esac
|
|
519
|
+
fi
|
|
520
|
+
|
|
521
|
+
# ── --wait ───────────────────────────────────────────────────────────────────────────────────
|
|
522
|
+
MAX_POLLS=$(( (TIMEOUT + 59) / 60 ))
|
|
523
|
+
prev=""
|
|
524
|
+
for (( poll = 1; poll <= MAX_POLLS; poll++ )); do
|
|
525
|
+
check_once; rc=$?
|
|
526
|
+
case "$rc" in
|
|
527
|
+
0) finish 0 ready ;;
|
|
528
|
+
4) finish 4 stale ;;
|
|
529
|
+
1) ;;
|
|
530
|
+
*) finish 3 error ;;
|
|
531
|
+
esac
|
|
532
|
+
# rc 1: a FAILED context, UNTRUSTED-CI or a base mismatch is terminal -- no point waiting.
|
|
533
|
+
if [[ "$J_FAILED" != "[]" || "$REASON" != "not-green" ]]; then finish 1 not-ready; fi
|
|
534
|
+
if [[ "$LINES" != "$prev" ]]; then
|
|
535
|
+
printf 'WAIT poll=%d/%d absent=%s pending=%s\n' "$poll" "$MAX_POLLS" "$J_ABSENT" "$J_PENDING"
|
|
536
|
+
prev="$LINES"
|
|
537
|
+
elif (( poll % 5 == 0 )); then
|
|
538
|
+
printf 'HEARTBEAT poll=%d/%d still waiting absent=%s pending=%s\n' \
|
|
539
|
+
"$poll" "$MAX_POLLS" "$J_ABSENT" "$J_PENDING"
|
|
540
|
+
fi
|
|
541
|
+
(( poll < MAX_POLLS )) && sleep "$POLL_SECONDS"
|
|
542
|
+
done
|
|
543
|
+
MSG="TIMEOUT: $MAX_POLLS polls spent with required contexts still absent or pending"
|
|
544
|
+
REASON=timeout
|
|
545
|
+
finish 1 timeout
|