@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
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# BEHIND resync — merge origin/main into the current PR branch and push.
|
|
3
|
+
#
|
|
4
|
+
# THE ONE IMPLEMENTATION of the Phase 7 BEHIND auto-sync (#8383). Three callers:
|
|
5
|
+
# 1. ship/SKILL.md Phase 7 poll fence — runs `sync-pr-behind.sh <n> --step --fence`
|
|
6
|
+
# 2. merge-pr/SKILL.md §5.2 mirror fence — runs `sync-pr-behind.sh <n> --step --fence`
|
|
7
|
+
# 3. standalone (Grok AwaitShell, review/SKILL.md's CONFLICTING-but-clean
|
|
8
|
+
# recovery) — runs `sync-pr-behind.sh <n> [--max-attempts N]`
|
|
9
|
+
# A fix to the merge/push path is made in sync_step() below and reaches all three. Two read-only modes serve other
|
|
10
|
+
# callers: `--queue-state` (the pre-merge hook, monitor-pr-checks.sh) and `--queue-wait` (the pre-merge hook).
|
|
11
|
+
# The fences keep their own `BEHIND detected` / `auto-sync N pushed` lines and their
|
|
12
|
+
# counters; this script owns the attempt and reports it.
|
|
13
|
+
#
|
|
14
|
+
# What one attempt does (sync_step), and why:
|
|
15
|
+
# 1. Refuses to touch an operation it did not start: MERGE_HEAD, or a rebase /
|
|
16
|
+
# cherry-pick / revert in progress -> kind=merge_in_progress (an unconditional
|
|
17
|
+
# `--abort` there discards the operator's staged resolution — measured, #8339).
|
|
18
|
+
# Detached HEAD -> kind=detached_head (git push would have no branch to update).
|
|
19
|
+
# 2. Fetches main with an explicit refspec (a worktree whose remote.origin.fetch does
|
|
20
|
+
# not map main would otherwise merge a STALE origin/main). Failure is exit 5: the
|
|
21
|
+
# poll skips and counts the attempt, and the next tick retries.
|
|
22
|
+
# 3. Merges origin/main with --no-edit, reading git's OWN exit status — captured
|
|
23
|
+
# before any display `tail`, since `cmd | tail` returns tail's 0 (#8339). rc 1
|
|
24
|
+
# with MERGE_HEAD is a conflict (or a rejecting pre-merge-commit hook) this
|
|
25
|
+
# attempt started: abort, exit 6. Any other rc with MERGE_HEAD arrived during the
|
|
26
|
+
# fetch window — left alone, exit 9. Non-zero without MERGE_HEAD is a refusal
|
|
27
|
+
# (dirty tree, untracked overwrite): nothing to abort, exit 10. A merge that
|
|
28
|
+
# moved nothing is exit 11 (GitHub's mergeStateStatus lags) — no push.
|
|
29
|
+
# 4. Pushes the merge commit so GitHub re-evaluates the queued auto-merge. A failure
|
|
30
|
+
# is exit 7 and retains the local merge commit.
|
|
31
|
+
# Before 1. Merge queue (#9454): a PR that is IN the merge queue is skipped before any
|
|
32
|
+
# git work — nothing merged or pushed: `--step` prints `kind=queued rc=11` and exits 11
|
|
33
|
+
# (the fences' uncounted sync_noop arm), the standalone loop `kind=queued rc=0`, exit 0. A push to a
|
|
34
|
+
# queued PR dequeues it, and the queue itself keeps the entry current. The read is
|
|
35
|
+
# queue_state_read() below, retried once on a transient failure, and is also the one
|
|
36
|
+
# shared read: `sync-pr-behind.sh <pr> --queue-state` prints it (the pre-merge hook and
|
|
37
|
+
# monitor-pr-checks.sh call that). It lives in THIS file, not a sibling, because the Phase 7
|
|
38
|
+
# fences run a frozen snapshot of this script that has no sibling files. A read that still
|
|
39
|
+
# fails is `kind=gh` (exit 4), NEVER "not queued" — that would push to a queued PR.
|
|
40
|
+
# Dequeue: a read that finds the PR OPEN, out of the queue, and either seen queued before (a
|
|
41
|
+
# marker in the per-worktree git dir, left by a queued sighting) or carrying a CURRENT
|
|
42
|
+
# RemovedFromMergeQueueEvent (newer than the auto-merge re-arm and than the head commit) is a
|
|
43
|
+
# dequeue — a failed merge_group run, or a removal: `kind=dequeued rc=13`, exit 13, nothing merged or
|
|
44
|
+
# pushed; the line has the reason and the recovery. Auto-merge state is NOT consulted (measured 2026-10-05,
|
|
45
|
+
# #9482: it stays armed after a failed_checks removal and GitHub re-queues the PR; a removed PR is
|
|
46
|
+
# reported whether or not it is still armed). One re-read after a short nap precedes the report, so the
|
|
47
|
+
# queue's own merge landing (not queued, OPEN, about to read MERGED) is never one. A PR with neither
|
|
48
|
+
# marker nor event keeps the old reading (not queued yet / re-enqueues itself after a push). A dequeue
|
|
49
|
+
# reached through the marker alone is reported ONCE: --step (exit 13) and --queue-state (the `dequeued` print) each
|
|
50
|
+
# consume the marker, so a PR the agent fixed and re-armed is not reported again. The
|
|
51
|
+
# fences reach this on a BEHIND tick via --step and on every 5th OPEN tick via --queue-state.
|
|
52
|
+
# Before 1. Armed BEHIND on a merge-queue repo (2026-10-09, PR 9839; extended to --step and the hook 2026-10-20, #9869): a PR
|
|
53
|
+
# that GitHub reports BEHIND or UNKNOWN (never DIRTY), with auto-merge armed and a merge_queue rule on main, is skipped
|
|
54
|
+
# before any git work — nothing fetched, merged or pushed. The window it closes is between the arm and the enqueue, where
|
|
55
|
+
# queue_gate sees no entry and a push restarts every required check for nothing. ONE predicate (queue_wait_eval() below)
|
|
56
|
+
# serves three callers: the standalone loop answers `kind=queue_wait` rc=0 (exit 0); a FLAGLESS `--step` answers
|
|
57
|
+
# `kind=queue_wait` rc=14 (exit 14: not 11, the fences' uncounted no-op arm, which an OLD pasted fence would loop on
|
|
58
|
+
# silently — 14 hits its loud sync_failed stop); `--queue-wait` prints the verdict (`queue_wait` | `proceed`) for the
|
|
59
|
+
# pre-merge hook. The Phase 7 fences pass `--fence`, which skips the guard entirely: the fence owns the queue-mode
|
|
60
|
+
# decision and its expiry fallback, and its legitimate sync arms (expiry, DIRTY-derived BEHIND, no merge_queue rule, a
|
|
61
|
+
# failed armed read) must still sync. `--fence` is accident prevention, not authentication.
|
|
62
|
+
# Every tagged line is `[pr-behind-sync] kind=<k> rc=<n> — …` on STDOUT (a Monitor
|
|
63
|
+
# streams stdout only). rc is git's own exit status where a git command failed, else
|
|
64
|
+
# this script's exit code. Exit codes: see usage() / --help — the one table.
|
|
65
|
+
#
|
|
66
|
+
# Any unrecognised argument exits 2. The strictness is load-bearing: an older copy
|
|
67
|
+
# silently ignored unknown flags, so `--step` ran a full standalone sync and exited 0
|
|
68
|
+
# on "no sync needed" — which a fence would print as `pushed`. The fences refuse a
|
|
69
|
+
# copy whose --help does not name --fence (a copy that predates the queue-armed
|
|
70
|
+
# refusal; --fence is valid only with --step, so a copy naming it has --step).
|
|
71
|
+
#
|
|
72
|
+
# Portability: runs on customer hosts including macOS's bash 3.2 — no mapfile, no
|
|
73
|
+
# ${x,,}, no associative arrays, no date; `timeout` only when present and `sleep` only between
|
|
74
|
+
# queue-read and rules-read retries (the Phase 7 fixture shadows date and sleep in the PARENT only and sets
|
|
75
|
+
# PR_QUEUE_RETRY_SLEEP=0 for the child).
|
|
76
|
+
# Preconditions: run from inside the PR feature worktree (not bare repo root).
|
|
77
|
+
set -euo pipefail
|
|
78
|
+
|
|
79
|
+
# git treats GIT_CURL_VERBOSE as on when merely PRESENT (even =0), and every trace knob
|
|
80
|
+
# can print token-bearing URLs and push result lines out of the `tail` windows below.
|
|
81
|
+
# Stripped once for every git call this process makes; the caller's shell is untouched.
|
|
82
|
+
unset GIT_CURL_VERBOSE GIT_TRACE GIT_TRACE_CURL GIT_TRACE_PACKET GIT_TRACE2 \
|
|
83
|
+
GIT_TRACE2_EVENT GIT_TRACE2_PERF GIT_TRACE_PERFORMANCE GIT_TRACE_SETUP
|
|
84
|
+
export GIT_TRACE_REDACT=1
|
|
85
|
+
|
|
86
|
+
usage() {
|
|
87
|
+
cat <<'USAGE'
|
|
88
|
+
usage: sync-pr-behind.sh <pr-number> [--max-attempts N]
|
|
89
|
+
sync-pr-behind.sh <pr-number> --step [--fence]
|
|
90
|
+
sync-pr-behind.sh <pr-number> --queue-state
|
|
91
|
+
sync-pr-behind.sh <pr-number> --queue-wait
|
|
92
|
+
sync-pr-behind.sh --help
|
|
93
|
+
|
|
94
|
+
Run from the PR's feature worktree, on its branch: the script syncs $PWD's branch.
|
|
95
|
+
|
|
96
|
+
--step one sync attempt on the current branch (merge origin/main, push).
|
|
97
|
+
A PR in the merge queue is skipped (a push would dequeue it). Without
|
|
98
|
+
--fence it also refuses an OPEN, armed PR that GitHub reports BEHIND or
|
|
99
|
+
UNKNOWN (never DIRTY) on a repo whose main has a merge_queue rule:
|
|
100
|
+
kind=queue_wait, exit 14, nothing fetched, merged or pushed (the queue
|
|
101
|
+
makes the PR current; a resync restarts every required check). The Phase
|
|
102
|
+
7 fence's call: the fence owns the queue-mode decision (rule, armed,
|
|
103
|
+
expiry); do not call it from your own loop
|
|
104
|
+
--fence with --step only: the Phase 7 / merge-pr poll fences pass this;
|
|
105
|
+
nobody else. It skips the queue-armed refusal (and its extra gh reads)
|
|
106
|
+
because the fence has already made that decision, expiry included
|
|
107
|
+
--queue-state print `<queued|not_queued|dequeued> <OPEN|CLOSED|MERGED> <armed|disarmed> removal=<reason|none>`
|
|
108
|
+
(the merge queue state; `dequeued` = out of the queue, OPEN, and seen queued or a current removal
|
|
109
|
+
event; no push, no worktree needed) and exit 0, or `kind=gh` exit 4 after one retry. Writes
|
|
110
|
+
nothing except to CONSUME the seen-queued marker when it prints `dequeued`: that verdict is
|
|
111
|
+
reported once, so a re-armed PR is not reported again (a current removal event needs no marker)
|
|
112
|
+
Env: PR_QUEUE_TIMEOUT (s, default 10), PR_QUEUE_ATTEMPTS (default 2 = one retry),
|
|
113
|
+
PR_QUEUE_RETRY_SLEEP (s, default 2), PR_QUEUE_REPO=OWNER/REPO (else the cwd repo);
|
|
114
|
+
the same four govern the merge-queue rule read; the pr view read honors only
|
|
115
|
+
PR_QUEUE_TIMEOUT and PR_QUEUE_REPO (one attempt, no retry)
|
|
116
|
+
--queue-wait print `queue_wait` or `proceed` and exit 0, or `kind=gh` exit 4 (a failed, hung or
|
|
117
|
+
unparseable read is never read as `proceed`). `queue_wait` = the PR is OPEN, GitHub
|
|
118
|
+
reports BEHIND or UNKNOWN (not DIRTY), auto-merge is armed and main has a merge_queue
|
|
119
|
+
rule. One pr view snapshot (state, mergeStateStatus, autoMergeRequest) and one rules
|
|
120
|
+
read; no GraphQL queue read, no worktree, nothing written. The pre-merge hook calls it
|
|
121
|
+
after --queue-state said not_queued. `--queue-state`: is the PR in the queue;
|
|
122
|
+
`--queue-wait`: should a sync be skipped. Env: PR_QUEUE_TIMEOUT and PR_QUEUE_REPO (the pr view read is a single attempt)
|
|
123
|
+
--max-attempts N standalone loop (N = 1..999): check the PR's head branch is the
|
|
124
|
+
current branch, read state, sync while BEHIND, up to N times
|
|
125
|
+
|
|
126
|
+
exit codes (each non-zero exit prints one tagged `kind=<k> rc=<n>` line on stdout):
|
|
127
|
+
0 synced and pushed (--step), or nothing to do / BEHIND resolved (standalone), or
|
|
128
|
+
the PR is in the merge queue — standalone only: skipped, nothing merged or pushed
|
|
129
|
+
(kind=queued; --step exits 11 for it, see below), or BEHIND + armed on a merge-queue
|
|
130
|
+
repo — standalone only: skipped, nothing fetched, merged or pushed (kind=queue_wait;
|
|
131
|
+
a flagless --step exits 14 for it, see below)
|
|
132
|
+
2 usage error or unknown argument (kind=usage)
|
|
133
|
+
3 not inside a work tree (kind=not_worktree)
|
|
134
|
+
4 a gh call failed (kind=gh): gh pr view (standalone, flagless --step, --queue-wait), the merge-queue
|
|
135
|
+
read after one retry, or (armed BEHIND PR) the main merge-queue rule read
|
|
136
|
+
5 fetching main failed (kind=fetch)
|
|
137
|
+
6 merge conflict, or merge not committed (hook) — the merge was aborted (kind=merge)
|
|
138
|
+
7 git push failed — the local merge commit is retained (kind=push)
|
|
139
|
+
8 still BEHIND after N attempts (standalone, kind=exhausted); after a kind=pushed
|
|
140
|
+
line the push landed and GitHub has not recomputed yet — re-arm the poll
|
|
141
|
+
9 a merge/rebase/cherry-pick/revert this script did not start, or detached HEAD
|
|
142
|
+
(kind=merge_in_progress or detached_head)
|
|
143
|
+
10 git merge refused to start (nothing to abort, kind=merge_refused)
|
|
144
|
+
11 origin/main already merged and pushed — nothing to push (kind=noop); GitHub's
|
|
145
|
+
mergeStateStatus lags the ref. Also --step on a PR in the merge queue: skipped,
|
|
146
|
+
nothing merged or pushed (kind=queued). Fences keep polling; standalone exits so the
|
|
147
|
+
caller re-runs once GitHub recomputes the state
|
|
148
|
+
12 the current branch is not the PR's head branch (standalone, kind=wrong_branch)
|
|
149
|
+
13 the PR is out of the merge queue, OPEN, and was seen queued or has a current removal event (a failed
|
|
150
|
+
merge_group run or a removal; kind=dequeued; auto-merge state is not consulted) — nothing merged or
|
|
151
|
+
pushed; the line has the removal reason and the recovery
|
|
152
|
+
14 flagless --step on an armed BEHIND/UNKNOWN PR of a merge-queue repo (kind=queue_wait): nothing fetched,
|
|
153
|
+
merged or pushed. kind=queue_wait carries rc 0 standalone and rc 14 under --step, so no consumer keys
|
|
154
|
+
on the kind alone
|
|
155
|
+
USAGE
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
tag() { local k="$1" r="$2"; shift 2; echo "[pr-behind-sync] kind=$k rc=$r — $*"; }
|
|
159
|
+
usage_err() { tag usage 2 "$1"; usage; exit 2; }
|
|
160
|
+
|
|
161
|
+
PR=""; MODE=loop; MAX_ATTEMPTS=1; FENCE=0; NMODE=0
|
|
162
|
+
while [[ $# -gt 0 ]]; do
|
|
163
|
+
case "$1" in
|
|
164
|
+
--help|-h) usage; exit 0 ;;
|
|
165
|
+
--step) MODE=step; NMODE=$((NMODE + 1)) ;;
|
|
166
|
+
--queue-state) MODE=queue_state; NMODE=$((NMODE + 1)) ;;
|
|
167
|
+
--queue-wait) MODE=queue_wait; NMODE=$((NMODE + 1)) ;;
|
|
168
|
+
--fence) FENCE=1 ;;
|
|
169
|
+
--max-attempts)
|
|
170
|
+
[[ "${2:-}" =~ ^[1-9][0-9]{0,2}$ ]] || usage_err "--max-attempts takes 1..999, got '${2:-}'"
|
|
171
|
+
MAX_ATTEMPTS="$2"; shift ;;
|
|
172
|
+
*)
|
|
173
|
+
if [[ -z "$PR" && "$1" =~ ^[0-9]+$ ]]; then PR="$1"; else usage_err "unexpected argument '$1'"; fi ;;
|
|
174
|
+
esac
|
|
175
|
+
shift
|
|
176
|
+
done
|
|
177
|
+
[[ -n "$PR" ]] || usage_err "missing <pr-number>"
|
|
178
|
+
# The strictness invariant: a mode-flag misuse is a usage error, never a quiet pick of one of them (an older copy that ignored
|
|
179
|
+
# unknown flags once printed a false "pushed").
|
|
180
|
+
if [[ "$NMODE" -gt 1 ]]; then usage_err "at most one of --step, --queue-state, --queue-wait"; fi
|
|
181
|
+
if [[ "$FENCE" == 1 && "$MODE" != step ]]; then usage_err "--fence is only valid with --step"; fi
|
|
182
|
+
if [[ "$MODE" != loop && "$MAX_ATTEMPTS" != 1 ]]; then usage_err "--step, --queue-state and --queue-wait take no --max-attempts"; fi
|
|
183
|
+
|
|
184
|
+
# queue_state_read — THE ONE copy of the merge-queue GraphQL read and its jq verdict program (the
|
|
185
|
+
# pre-merge hook and monitor-pr-checks.sh reach it through --queue-state). Sets QS_OUT to
|
|
186
|
+
# `<queued|not_queued> <state> <armed|disarmed> removal=<reason|none>` (`-` for a field the answer lacks;
|
|
187
|
+
# removal = the newest RemovedFromMergeQueueEvent, only while it is CURRENT: newer than the auto-merge re-arm
|
|
188
|
+
# and than the head commit, so a fixed-and-pushed or re-armed PR reads none) and returns 0, or
|
|
189
|
+
# sets QS_CAUSE (timeout | gh_error | unparseable) and QS_DETAIL and returns 1: a failed read is
|
|
190
|
+
# NEVER a verdict. `{owner}` / `{repo}` are filled by gh from the cwd repository (PR_QUEUE_REPO=o/r
|
|
191
|
+
# overrides). Both queue fields are read (an entry exists iff isInMergeQueue); the call runs under
|
|
192
|
+
# `bash -c` so a gh that is a shell function (an exported test mock) is still reached, and under
|
|
193
|
+
# timeout/gtimeout when present so a hung call cannot hang a poll tick or a hook.
|
|
194
|
+
queue_state_read() {
|
|
195
|
+
local to_s="${PR_QUEUE_TIMEOUT:-10}" attempts="${PR_QUEUE_ATTEMPTS:-2}" nap="${PR_QUEUE_RETRY_SLEEP:-2}"
|
|
196
|
+
local owner='{owner}' repo='{repo}' n=0 rc out errf query jqp
|
|
197
|
+
[[ "$to_s" =~ ^[1-9][0-9]{0,3}$ ]] || to_s=10
|
|
198
|
+
[[ "$attempts" =~ ^[1-9]$ ]] || attempts=2
|
|
199
|
+
[[ "$nap" =~ ^[0-9]{1,3}$ ]] || nap=2
|
|
200
|
+
if [[ "${PR_QUEUE_REPO:-}" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]]; then owner="${PR_QUEUE_REPO%%/*}"; repo="${PR_QUEUE_REPO#*/}"; fi
|
|
201
|
+
local to=()
|
|
202
|
+
if command -v timeout >/dev/null 2>&1; then to=(timeout -k 2 "$to_s")
|
|
203
|
+
elif command -v gtimeout >/dev/null 2>&1; then to=(gtimeout -k 2 "$to_s"); fi
|
|
204
|
+
# shellcheck disable=SC2016 # the GraphQL `$owner`/`$name`/`$number` are variables of the query, not shell
|
|
205
|
+
query='
|
|
206
|
+
query($owner: String!, $name: String!, $number: Int!) {
|
|
207
|
+
repository(owner: $owner, name: $name) {
|
|
208
|
+
pullRequest(number: $number) {
|
|
209
|
+
isInMergeQueue mergeQueueEntry { state } state autoMergeRequest { enabledAt }
|
|
210
|
+
commits(last: 1) { nodes { commit { committedDate } } }
|
|
211
|
+
timelineItems(last: 1, itemTypes: [REMOVED_FROM_MERGE_QUEUE_EVENT]) { nodes { ... on RemovedFromMergeQueueEvent { reason createdAt } } }
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}'
|
|
215
|
+
# shellcheck disable=SC2016 # `$r` / `$en` / `$hd` are jq variables, not shell
|
|
216
|
+
jqp='.data.repository.pullRequest
|
|
217
|
+
| if . == null then "unreadable"
|
|
218
|
+
else (if .isInMergeQueue == true or .mergeQueueEntry != null then "queued"
|
|
219
|
+
elif .isInMergeQueue == false then "not_queued"
|
|
220
|
+
else "unreadable" end)
|
|
221
|
+
+ " " + (.state // "-")
|
|
222
|
+
+ " " + (if has("autoMergeRequest") then (if .autoMergeRequest == null then "disarmed" else "armed" end) else "-" end)
|
|
223
|
+
+ " removal=" + (if has("timelineItems") then
|
|
224
|
+
(.timelineItems.nodes // [])[0] as $r
|
|
225
|
+
| (.autoMergeRequest.enabledAt // "") as $en
|
|
226
|
+
| ((.commits.nodes // [])[0].commit.committedDate // "") as $hd
|
|
227
|
+
| if $r == null or ($r.createdAt // "") <= $en or ($r.createdAt // "") <= $hd then "none"
|
|
228
|
+
else (($r.reason // "unknown") | tostring | gsub("[^A-Za-z0-9_-]"; "_")) end
|
|
229
|
+
else "-" end)
|
|
230
|
+
end'
|
|
231
|
+
errf="$(mktemp)" || { QS_CAUSE=gh_error; QS_DETAIL="mktemp failed"; return 1; } # lint-trap-ownership: ok — removed by rm -f on every return path of queue_state_read; a kill leaves one tiny file
|
|
232
|
+
while [[ "$n" -lt "$attempts" ]]; do
|
|
233
|
+
n=$((n + 1)); rc=0
|
|
234
|
+
# shellcheck disable=SC2016 # $1..$5 are bash -c's own positional parameters, not this shell's
|
|
235
|
+
out="$(${to[@]+"${to[@]}"} bash -c 'gh api graphql -F owner="$4" -F name="$5" -F number="$1" -f query="$2" --jq "$3"' \
|
|
236
|
+
_ "$PR" "$query" "$jqp" "$owner" "$repo" 2>"$errf")" || rc=$?
|
|
237
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
238
|
+
case "$rc" in 124|137|143) QS_CAUSE=timeout ;; *) QS_CAUSE=gh_error ;; esac
|
|
239
|
+
# gh's raw stderr reaches the `kind=gh rc=4` line a Monitor streams to the model: ESC, CR and a forged tag line must not.
|
|
240
|
+
QS_DETAIL="$(printf '%s' "rc=$rc $(head -c 200 "$errf")" | tr -c '[:alnum:] ._:/=-' '?')"
|
|
241
|
+
else
|
|
242
|
+
out="${out%%$'\n'*}"
|
|
243
|
+
case "${out%% *}" in
|
|
244
|
+
queued|not_queued) rm -f "$errf"; QS_OUT="$out"; return 0 ;;
|
|
245
|
+
*) QS_CAUSE=unparseable; QS_DETAIL="read returned '${out:0:80}' (want queued or not_queued)" ;;
|
|
246
|
+
esac
|
|
247
|
+
fi
|
|
248
|
+
if [[ "$n" -lt "$attempts" ]]; then sleep "$nap"; fi
|
|
249
|
+
done
|
|
250
|
+
rm -f "$errf"
|
|
251
|
+
return 1
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# dq_candidate <marker> — 0 iff QS_OUT reads the PR out of the queue and OPEN AND it either was seen queued (the
|
|
255
|
+
# marker, per worktree git dir) or has a CURRENT removal event. Auto-merge state is NOT consulted: after a failed
|
|
256
|
+
# merge_group run it stays armed (measured 2026-10-05, #9482, two PRs) and GitHub may re-queue the PR, and a
|
|
257
|
+
# removed PR must be reported whether or not it is still armed. Only a PR with
|
|
258
|
+
# neither marker nor event keeps the old reading (not queued yet, or a push dequeued it and it re-enqueues itself).
|
|
259
|
+
dq_candidate() {
|
|
260
|
+
local v st am rm
|
|
261
|
+
read -r v st am rm <<<"$QS_OUT"
|
|
262
|
+
[[ "$v" == not_queued && "$st" == OPEN ]] || return 1
|
|
263
|
+
[[ ( -n "$1" && -f "$1" ) || ( -n "$rm" && "$rm" != removal=none && "$rm" != removal=- ) ]]
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# queue_read_settled <marker> — queue_state_read, then ONE re-read after a short nap when the first answer is a
|
|
267
|
+
# dequeue candidate, so the instant the queue's own merge lands (not queued, OPEN, about to read MERGED) is never
|
|
268
|
+
# reported as a dequeue. Returns 1 (QS_CAUSE set) when either read fails: a failed read is never a verdict.
|
|
269
|
+
queue_read_settled() {
|
|
270
|
+
local nap="${PR_QUEUE_RETRY_SLEEP:-2}"
|
|
271
|
+
[[ "$nap" =~ ^[0-9]{1,3}$ ]] || nap=2
|
|
272
|
+
queue_state_read || return 1
|
|
273
|
+
if dq_candidate "$1"; then sleep "$nap"; queue_state_read || return 1; fi
|
|
274
|
+
return 0
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
# queue_wait_eval — THE ONE copy of the armed-BEHIND predicate (2026-10-09, PR 9839; shared with --step and --queue-wait,
|
|
278
|
+
# #9869). Between `gh pr merge --auto` and the enqueue a PR is OPEN, BEHIND, armed and NOT in the queue, so queue_gate (which
|
|
279
|
+
# only sees an entry) lets it through, and a sync there pushes a commit that restarts every required check for nothing: on a
|
|
280
|
+
# merge-queue repo the queue makes the PR current itself. Fires when the PR is OPEN, GitHub says BEHIND or UNKNOWN (UNKNOWN is
|
|
281
|
+
# recompute lag; DIRTY never: a conflicting or kb-index-class PR still resolves) AND auto-merge is armed AND `main` has a
|
|
282
|
+
# merge_queue rule (one rules read, selected by `.type`, never by position: merge_queue is not the first rule on a live repo, and
|
|
283
|
+
# the read asks for 100 rules per page: a merge_queue beyond rule 100 would read as absent). It always RETURNS 0 and reports
|
|
284
|
+
# through QW_VERDICT (wait | proceed | unreadable) and QW_DETAIL: a distinct non-zero return would kill a caller under
|
|
285
|
+
# `set -euo pipefail` on the common proceed path. A rules read that still fails after PR_QUEUE_ATTEMPTS tries (default 2, like
|
|
286
|
+
# queue_state_read), or answers empty or non-numeric, is `unreadable`: the one place this script fails CLOSED on an unreadable
|
|
287
|
+
# rules answer (ADR-270 addendum 2026-10-09) — an unknown answer is not a yes. The cause is in QW_DETAIL. Base is `main`.
|
|
288
|
+
queue_wait_eval() { # <state_line: "<STATE> <MERGESTATE>"> <armed|disarmed|->
|
|
289
|
+
local am="$2" out="" rc=0 n=0 detail="" errf owner='{owner}' repo='{repo}'
|
|
290
|
+
local to_s="${PR_QUEUE_TIMEOUT:-10}" attempts="${PR_QUEUE_ATTEMPTS:-2}" nap="${PR_QUEUE_RETRY_SLEEP:-2}" to=()
|
|
291
|
+
QW_VERDICT=proceed; QW_DETAIL=""
|
|
292
|
+
[[ "$1" == OPEN\ * ]] || return 0
|
|
293
|
+
[[ ( "$1" == *BEHIND* || "$1" == *UNKNOWN* ) && "$1" != *DIRTY* ]] || return 0
|
|
294
|
+
[[ "$am" == armed ]] || return 0
|
|
295
|
+
[[ "$to_s" =~ ^[1-9][0-9]{0,3}$ ]] || to_s=10
|
|
296
|
+
[[ "$attempts" =~ ^[1-9]$ ]] || attempts=2
|
|
297
|
+
[[ "$nap" =~ ^[0-9]{1,3}$ ]] || nap=2
|
|
298
|
+
if [[ "${PR_QUEUE_REPO:-}" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]]; then owner="${PR_QUEUE_REPO%%/*}"; repo="${PR_QUEUE_REPO#*/}"; fi
|
|
299
|
+
if command -v timeout >/dev/null 2>&1; then to=(timeout -k 2 "$to_s")
|
|
300
|
+
elif command -v gtimeout >/dev/null 2>&1; then to=(gtimeout -k 2 "$to_s"); fi
|
|
301
|
+
errf="$(mktemp)" || { QW_VERDICT=unreadable; QW_DETAIL="rule read not attempted (mktemp failed)"; return 0; } # lint-trap-ownership: ok — removed by rm -f on every return path of queue_wait_eval; a kill leaves one tiny file
|
|
302
|
+
while [[ "$n" -lt "$attempts" ]]; do
|
|
303
|
+
n=$((n + 1)); rc=0
|
|
304
|
+
# shellcheck disable=SC2016 # $1..$3 are bash -c's own positional parameters, not this shell's
|
|
305
|
+
out="$(${to[@]+"${to[@]}"} bash -c 'gh api "repos/$1/$2/rules/branches/main?per_page=100" --jq "$3"' \
|
|
306
|
+
_ "$owner" "$repo" '[.[] | select(.type == "merge_queue")] | length' 2>"$errf")" || rc=$?
|
|
307
|
+
out="${out%%$'\n'*}"
|
|
308
|
+
if [[ "$rc" -eq 0 && "$out" =~ ^[0-9]{1,6}$ ]]; then break; fi
|
|
309
|
+
detail="rc=$rc answered=${out:0:40} $(head -c 160 "$errf" | tr '\n' ' ')"
|
|
310
|
+
if [[ "$n" -lt "$attempts" ]]; then sleep "$nap"; fi
|
|
311
|
+
done
|
|
312
|
+
rm -f "$errf"
|
|
313
|
+
if [[ "$rc" -eq 0 && "$out" =~ ^[0-9]{1,6}$ ]]; then
|
|
314
|
+
if (( 10#$out >= 1 )); then QW_VERDICT="wait"; QW_DETAIL="rules=$out"; fi
|
|
315
|
+
return 0
|
|
316
|
+
fi
|
|
317
|
+
detail="$(printf '%s' "$detail" | tr -c '[:alnum:] ._:/=-' '?')"
|
|
318
|
+
QW_VERDICT=unreadable; QW_DETAIL="rule read failed after $n attempt(s) ($detail)"
|
|
319
|
+
return 0
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
# The refusal text shared by every caller that refuses (the standalone loop, a flagless --step): what to do instead of a resync.
|
|
323
|
+
qw_refusal() {
|
|
324
|
+
printf '%s' "PR #$PR is BEHIND, auto-merge is armed (not in the queue yet) and main has a merge queue: not syncing — a resync alone restarts every required check and the queue makes the PR current. Wait for MERGED or a dequeue; with no poll running, re-arm the Phase 7 poll with CLAUDE_PLUGIN_ROOT exported — its expiry fallback after 6 idle ticks is the sanctioned sync. Red required check? Push the fix itself, not a resync. Truly need a hand sync? Disarm first (gh pr merge $PR --disable-auto), sync, then re-arm. Green and never enqueued? Follow plugins/soleur/skills/ship/references/merge-queue-dequeue.md ('Armed and green but never enqueued')."
|
|
325
|
+
}
|
|
326
|
+
# ... and the unreadable-rules text (fail closed): an unknown answer is not a yes.
|
|
327
|
+
qw_unreadable() { # <detail>
|
|
328
|
+
printf '%s' "merge-queue $1 — not syncing: that read decides whether this armed BEHIND PR may be resynced and an unknown answer is not a yes. Retry the poll; a persistent failure means the token cannot read repository rules (raise PR_QUEUE_ATTEMPTS, or resync by hand only after confirming main has no merge queue)."
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
# qw_snapshot — ONE bounded `gh pr view <PR> --json state,mergeStateStatus,autoMergeRequest` for the flagless --step and --queue-wait
|
|
332
|
+
# (no GraphQL queue read: --queue-wait's caller already classified queued / not_queued, and a second read would race a
|
|
333
|
+
# just-dequeued PR that still reads armed). Sets QW_STATE (`<STATE> <MERGESTATE>`) and QW_ARMED (armed | disarmed). It runs under
|
|
334
|
+
# the same timeout wrapper and PR_QUEUE_REPO handling as the other reads, with gh's stderr kept OUT of the string the match
|
|
335
|
+
# tests, and a strict match on the answer. ANY failure — non-zero, hung, empty, garbage — is `kind=gh` exit 4: never read as "not armed".
|
|
336
|
+
qw_snapshot() {
|
|
337
|
+
local to_s="${PR_QUEUE_TIMEOUT:-10}" out="" rc=0 errf pvd repo_arg="" to=()
|
|
338
|
+
[[ "$to_s" =~ ^[1-9][0-9]{0,3}$ ]] || to_s=10
|
|
339
|
+
if [[ "${PR_QUEUE_REPO:-}" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]]; then repo_arg="$PR_QUEUE_REPO"; fi
|
|
340
|
+
if command -v timeout >/dev/null 2>&1; then to=(timeout -k 2 "$to_s")
|
|
341
|
+
elif command -v gtimeout >/dev/null 2>&1; then to=(gtimeout -k 2 "$to_s"); fi
|
|
342
|
+
errf="$(mktemp)" || { tag gh 4 "pr view snapshot not attempted (mktemp failed) — not syncing; retry the poll"; exit 4; } # lint-trap-ownership: ok — removed by rm -f on every path of qw_snapshot; a kill leaves one tiny file
|
|
343
|
+
# shellcheck disable=SC2016 # $1..$3 are bash -c's own positional parameters, not this shell's
|
|
344
|
+
out="$(${to[@]+"${to[@]}"} bash -c 'if [[ -n "$3" ]]; then gh pr view "$1" --repo "$3" --json state,mergeStateStatus,autoMergeRequest --jq "$2"; else gh pr view "$1" --json state,mergeStateStatus,autoMergeRequest --jq "$2"; fi' \
|
|
345
|
+
_ "$PR" '"\(.state) \(.mergeStateStatus) \(if .autoMergeRequest == null then "disarmed" else "armed" end)"' "$repo_arg" 2>"$errf")" || rc=$?
|
|
346
|
+
out="${out%%$'\n'*}"
|
|
347
|
+
if [[ "$rc" -eq 0 && "$out" =~ ^(OPEN|CLOSED|MERGED)\ [A-Z_]+\ (armed|disarmed)$ ]]; then
|
|
348
|
+
rm -f "$errf"
|
|
349
|
+
QW_STATE="${out% *}"; QW_ARMED="${out##* }"
|
|
350
|
+
return 0
|
|
351
|
+
fi
|
|
352
|
+
pvd="$(printf '%s' "rc=$rc answered=${out:0:40} $(head -c 160 "$errf")" | tr -c '[:alnum:] ._:/=-' '?')"
|
|
353
|
+
rm -f "$errf"
|
|
354
|
+
tag gh 4 "pr view snapshot read failed ($pvd) — not syncing: whether this PR is armed and BEHIND decides if a resync is allowed, and an unknown answer is not a yes. Retry."
|
|
355
|
+
exit 4
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
# --queue-wait: the read-only verdict for the pre-merge hook (#9869), handled beside --queue-state before the worktree check.
|
|
359
|
+
# Armed means autoMergeRequest != null in THIS snapshot, so an armed PR that is already in the queue also reads queue_wait (the
|
|
360
|
+
# stricter, safe direction for a caller that decides whether to push). Writes nothing — no marker.
|
|
361
|
+
if [[ "$MODE" == queue_wait ]]; then
|
|
362
|
+
QW_STATE=""; QW_ARMED=""
|
|
363
|
+
qw_snapshot
|
|
364
|
+
queue_wait_eval "$QW_STATE" "$QW_ARMED"
|
|
365
|
+
case "$QW_VERDICT" in
|
|
366
|
+
wait) echo queue_wait; exit 0 ;;
|
|
367
|
+
unreadable) tag gh 4 "$(qw_unreadable "$QW_DETAIL")"; exit 4 ;;
|
|
368
|
+
esac
|
|
369
|
+
echo proceed; exit 0
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
# step_guard — a FLAGLESS --step (#9869): refuse an armed BEHIND/UNKNOWN PR of a merge-queue repo with exit 14, a code of its
|
|
373
|
+
# own. 11 is the fences' uncounted "no sync needed" arm, so an OLD pasted fence would loop silently on it; 14 reaches its `*)`
|
|
374
|
+
# arm, a loud bounded stop whose line above names the action. The line opens with "NOT AN ERROR in itself" so an errexit reader
|
|
375
|
+
# does not fall back to a hand merge. Unreadable is fail closed (kind=gh, exit 4), as in the standalone loop.
|
|
376
|
+
step_guard() {
|
|
377
|
+
QW_STATE=""; QW_ARMED=""
|
|
378
|
+
qw_snapshot
|
|
379
|
+
queue_wait_eval "$QW_STATE" "$QW_ARMED"
|
|
380
|
+
case "$QW_VERDICT" in
|
|
381
|
+
wait) tag queue_wait 14 "NOT AN ERROR in itself (GitHub says: $QW_STATE) — exit 14 means this caller is not the current Phase 7 fence: re-READ ship/SKILL.md from disk and re-paste its fence (a copy held in context predates --fence); the PR itself needs no sync. $(qw_refusal)"
|
|
382
|
+
exit 14 ;;
|
|
383
|
+
unreadable) tag gh 4 "$(qw_unreadable "$QW_DETAIL")"; exit 4 ;;
|
|
384
|
+
esac
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
# --queue-state: the shared read — no git work, no worktree needed, no push. It never WRITES the marker (only --step does,
|
|
388
|
+
# on a queued sighting); the one write it makes is the CONSUMPTION below: printing `dequeued` removes the marker, so the
|
|
389
|
+
# report is delivered once (a PR the agent fixed and re-armed — CI running, not queued yet — must not read dequeued on every
|
|
390
|
+
# later tick just because the marker outlived the first report). Handled before the worktree check so a caller outside a
|
|
391
|
+
# work tree (monitor-pr-checks.sh --repo) can use it.
|
|
392
|
+
if [[ "$MODE" == queue_state ]]; then
|
|
393
|
+
QS_OUT=""; QS_CAUSE=""; QS_DETAIL=""
|
|
394
|
+
qs_marker="$(git rev-parse --git-dir 2>/dev/null || true)"; [[ -z "$qs_marker" ]] || qs_marker="$qs_marker/pr-queue-seen-$PR"
|
|
395
|
+
if queue_read_settled "$qs_marker"; then
|
|
396
|
+
# The verdict a caller acts on: `dequeued` replaces `not_queued` for a candidate that survived the re-read. A
|
|
397
|
+
# dequeue reached through the MARKER alone (removal=none) is reported ONCE: the report consumes the marker, exactly
|
|
398
|
+
# as --step does on exit 13. A dequeue from a CURRENT removal event needs no marker (a re-arm after the fix makes
|
|
399
|
+
# the event older than enabledAt, so it stops matching); a stale marker beside one is consumed by the same report.
|
|
400
|
+
# A non-dequeued verdict (queued, MERGED, not_queued) never consumes it.
|
|
401
|
+
if dq_candidate "$qs_marker"; then
|
|
402
|
+
QS_OUT="dequeued ${QS_OUT#* }"
|
|
403
|
+
[[ -z "$qs_marker" ]] || rm -f "$qs_marker" # consume-on-report
|
|
404
|
+
fi
|
|
405
|
+
printf '%s\n' "$QS_OUT"; exit 0
|
|
406
|
+
fi
|
|
407
|
+
tag gh 4 "merge queue read failed (cause=$QS_CAUSE ${QS_DETAIL:0:200}) — queue state unknown"
|
|
408
|
+
exit 4
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
# No `cd`: this script syncs the CALLER's worktree ($PWD). Resolving it from BASH_SOURCE
|
|
412
|
+
# synced the wrong repository (#8428) — pinned by the "SUT outside repo" test case.
|
|
413
|
+
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
414
|
+
tag not_worktree 3 "not inside a work tree — cd to the PR worktree (.worktrees/<branch>) and re-run"
|
|
415
|
+
exit 3
|
|
416
|
+
fi
|
|
417
|
+
|
|
418
|
+
BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo HEAD)"
|
|
419
|
+
|
|
420
|
+
# Merge-queue gate (#9454). Exits 11 in --step mode, 0 in the loop (kind=queued) when the PR is in the merge queue,
|
|
421
|
+
# 13 (kind=dequeued) when it is out of the queue, OPEN, and either was seen queued or has a CURRENT removal event
|
|
422
|
+
# (auto-merge state is not consulted), and 4 (kind=gh) when the read fails or answers anything but queued /
|
|
423
|
+
# not_queued; returns normally only on a positive "not queued" with no dequeue evidence. The read is
|
|
424
|
+
# queue_read_settled() above (queue_state_read owns the query and the verdict program; two attempts ride out a
|
|
425
|
+
# transient 5xx or rate limit, and a dequeue candidate is re-read once), so the fence needs no arm of its own.
|
|
426
|
+
queue_gate() {
|
|
427
|
+
local verdict st am rm marker git_dir reason
|
|
428
|
+
git_dir="$(git rev-parse --git-dir 2>/dev/null || true)"
|
|
429
|
+
marker=""; [[ -z "$git_dir" ]] || marker="$git_dir/pr-queue-seen-$PR"
|
|
430
|
+
QS_OUT=""; QS_CAUSE=""; QS_DETAIL=""
|
|
431
|
+
if ! queue_read_settled "$marker"; then
|
|
432
|
+
tag gh 4 "merge queue read failed (cause=$QS_CAUSE ${QS_DETAIL:0:200}) — not syncing; a push to a queued PR would dequeue it"
|
|
433
|
+
exit 4
|
|
434
|
+
fi
|
|
435
|
+
read -r verdict st am rm <<<"$QS_OUT"
|
|
436
|
+
case "$verdict" in
|
|
437
|
+
not_queued)
|
|
438
|
+
case "$st" in
|
|
439
|
+
MERGED|CLOSED) # the PR left the queue by merging (or was closed): a stale marker is cleared, nothing to sync
|
|
440
|
+
[[ -z "$marker" ]] || rm -f "$marker"
|
|
441
|
+
tag noop 11 "PR #$PR is $st — it left the queue; nothing to sync"
|
|
442
|
+
exit 11 ;;
|
|
443
|
+
esac
|
|
444
|
+
if dq_candidate "$marker"; then
|
|
445
|
+
[[ -z "$marker" ]] || rm -f "$marker"
|
|
446
|
+
reason="removal reason: ${rm#removal=}"
|
|
447
|
+
[[ "$rm" != removal=none && "$rm" != removal=- ]] || reason="seen in the queue earlier, no removal event read"
|
|
448
|
+
tag dequeued 13 "PR #$PR was in the merge queue and is no longer (OPEN, $am, $reason): a failed merge_group run or a removal — NOT syncing. Recover (ONE re-enqueue, procedure: plugins/soleur/skills/ship/references/merge-queue-dequeue.md): (1) read why: gh run list --event merge_group --limit 100 --json databaseId,headBranch,conclusion,url --jq '.[] | select(.headBranch | startswith(\"gh-readonly-queue/main/pr-$PR-\"))' then gh run view <databaseId> --log-failed; (2) fix on the branch, git merge origin/main, push; (3) re-arm once: gh pr merge $PR --squash --auto. A second dequeue: stop and report it."
|
|
449
|
+
exit 13
|
|
450
|
+
fi
|
|
451
|
+
return 0 ;;
|
|
452
|
+
queued)
|
|
453
|
+
[[ -z "$marker" ]] || { touch "$marker" 2>/dev/null || true; }
|
|
454
|
+
# --step exits 11 (the fence's uncounted no-op arm: nothing was pushed, so the ship and
|
|
455
|
+
# merge-pr fences must not count a sync); the standalone loop exits 0.
|
|
456
|
+
if [[ "$MODE" == step ]]; then
|
|
457
|
+
tag queued 11 "PR #$PR is in the merge queue; sync skipped (a push would dequeue it) — keep polling for MERGED or removal from the queue"
|
|
458
|
+
exit 11
|
|
459
|
+
fi
|
|
460
|
+
tag queued 0 "PR #$PR is in the merge queue; sync skipped (a push would dequeue it) — keep polling for MERGED or removal from the queue"
|
|
461
|
+
exit 0 ;;
|
|
462
|
+
*)
|
|
463
|
+
tag gh 4 "merge queue read returned '${QS_OUT:0:80}' (want queued or not_queued) — not syncing; a push to a queued PR would dequeue it"
|
|
464
|
+
exit 4 ;;
|
|
465
|
+
esac
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
# Armed-and-BEHIND gate for the standalone loop (2026-10-09, PR 9839): queue_wait_eval's verdict, as the loop answers it. Runs
|
|
469
|
+
# after queue_gate, whose QS_OUT carries the armed bit (no extra call). `wait` -> `kind=queue_wait` rc=0, exit 0 with nothing
|
|
470
|
+
# fetched, merged or pushed; `proceed` -> return, the sync goes on; `unreadable` -> `kind=gh` exit 4. The standalone answer has NO
|
|
471
|
+
# expiry of its own: re-arming the Phase 7 poll is the bound (its fallback sync).
|
|
472
|
+
queue_wait_gate() { # <state_line>
|
|
473
|
+
local v st am rm
|
|
474
|
+
read -r v st am rm <<<"$QS_OUT"
|
|
475
|
+
queue_wait_eval "$1" "$am"
|
|
476
|
+
case "$QW_VERDICT" in
|
|
477
|
+
wait) tag queue_wait 0 "$(qw_refusal)"; exit 0 ;;
|
|
478
|
+
unreadable) tag gh 4 "$(qw_unreadable "$QW_DETAIL")"; exit 4 ;;
|
|
479
|
+
esac
|
|
480
|
+
return 0
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
# One sync attempt. Returns the exit code documented in usage() and prints the tagged
|
|
484
|
+
# line for every non-zero outcome. Every git rc is captured with `|| rc=$?` before any
|
|
485
|
+
# display. Callers run it as `sync_step || rc=$?` (errexit is suspended inside); the
|
|
486
|
+
# `|| true` on display pipes keeps a future bare call from dying before the --abort.
|
|
487
|
+
sync_step() {
|
|
488
|
+
local git_dir rc out before conflicted
|
|
489
|
+
git_dir="$(git rev-parse --git-dir 2>/dev/null || true)"
|
|
490
|
+
if git rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1 \
|
|
491
|
+
|| [[ -n "$git_dir" && ( -d "$git_dir/rebase-merge" || -d "$git_dir/rebase-apply" \
|
|
492
|
+
|| -f "$git_dir/CHERRY_PICK_HEAD" || -f "$git_dir/REVERT_HEAD" ) ]]; then
|
|
493
|
+
tag merge_in_progress 9 "a merge/rebase/cherry-pick/revert is in progress on $BRANCH; not touching it. If you did not start it (a previous poll may have died mid-sync), run git status, abort it, then re-arm the poll."
|
|
494
|
+
return 9
|
|
495
|
+
fi
|
|
496
|
+
if ! git symbolic-ref -q HEAD >/dev/null 2>&1; then
|
|
497
|
+
tag detached_head 9 "HEAD is detached; git push would have no branch to update. Check out the PR branch first — run the poll from the PR worktree."
|
|
498
|
+
return 9
|
|
499
|
+
fi
|
|
500
|
+
|
|
501
|
+
rc=0; out="$(git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main 2>&1)" || rc=$?
|
|
502
|
+
if [[ -n "$out" ]]; then printf '%s\n' "$out" | tail -2 || true; fi
|
|
503
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
504
|
+
tag fetch "$rc" "fetch origin main failed"
|
|
505
|
+
return 5
|
|
506
|
+
fi
|
|
507
|
+
|
|
508
|
+
before="$(git rev-parse HEAD 2>/dev/null || true)"
|
|
509
|
+
rc=0; out="$(git merge origin/main --no-edit 2>&1)" || rc=$?
|
|
510
|
+
if [[ -n "$out" ]]; then printf '%s\n' "$out" | tail -5 || true; fi
|
|
511
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
512
|
+
if [[ "$rc" -eq 1 ]] && git rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1; then
|
|
513
|
+
# rerere.autoupdate can empty --diff-filter=U; the merge output cannot.
|
|
514
|
+
conflicted="$( { git diff --name-only --diff-filter=U 2>/dev/null || true; printf '%s\n' "$out" | grep '^CONFLICT ' || true; } )"
|
|
515
|
+
if [[ -n "$conflicted" ]]; then
|
|
516
|
+
tag merge "$rc" "git merge origin/main failed — merge conflict, aborting sync. Conflicted paths:"
|
|
517
|
+
printf '%s\n' "$conflicted"
|
|
518
|
+
else
|
|
519
|
+
tag merge "$rc" "git merge origin/main failed — merge not committed (hook rejected?), no conflicted paths; aborting sync."
|
|
520
|
+
fi
|
|
521
|
+
git merge --abort 2>&1 || echo "git merge --abort failed (rc=$?)"
|
|
522
|
+
if [[ -n "$conflicted" ]]; then
|
|
523
|
+
echo "Manual conflict resolution required on $BRANCH. Next: git merge origin/main, resolve, commit, push, then re-arm the poll."
|
|
524
|
+
else
|
|
525
|
+
echo "No conflict on $BRANCH. Next: run git merge origin/main and read the pre-merge-commit hook's output; fix what it reports, commit, push, then re-arm the poll."
|
|
526
|
+
fi
|
|
527
|
+
return 6
|
|
528
|
+
elif git rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1; then
|
|
529
|
+
tag merge_in_progress "$rc" "MERGE_HEAD appeared during the sync (not started by this script); not touching it. Run git status, finish or abort it, then re-arm the poll."
|
|
530
|
+
return 9
|
|
531
|
+
fi
|
|
532
|
+
tag merge_refused "$rc" "git merge origin/main failed — refused to start (nothing to abort; run git status to see which operation is in progress). Worktree state:"
|
|
533
|
+
git status --short 2>&1 | head -20 || true
|
|
534
|
+
echo "Clear the worktree state on $BRANCH shown above, then re-run the Phase 7 poll (or this script)."
|
|
535
|
+
return 10
|
|
536
|
+
fi
|
|
537
|
+
|
|
538
|
+
# Nothing merged AND nothing unpushed: GitHub's BEHIND is stale. A retained merge
|
|
539
|
+
# commit from an earlier failed push (HEAD != upstream) still gets pushed below.
|
|
540
|
+
if [[ -n "$before" && "$(git rev-parse HEAD 2>/dev/null || true)" == "$before" \
|
|
541
|
+
&& "$(git rev-parse '@{u}' 2>/dev/null || true)" == "$before" ]]; then
|
|
542
|
+
tag noop 11 "origin/main is already merged into $BRANCH and pushed; nothing to push. GitHub's mergeStateStatus lags — keep polling."
|
|
543
|
+
return 11
|
|
544
|
+
fi
|
|
545
|
+
|
|
546
|
+
rc=0; out="$(git push 2>&1)" || rc=$?
|
|
547
|
+
if [[ -n "$out" ]]; then printf '%s\n' "$out" | tail -2 || true; fi
|
|
548
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
549
|
+
tag push "$rc" "git push failed after merge — auto-sync incomplete; the local merge commit is retained, nothing was aborted. Usually a concurrent push to $BRANCH: run git fetch origin $BRANCH, inspect git log --oneline HEAD...origin/$BRANCH, then git merge origin/$BRANCH (do not rebase — it would flatten the retained merge commit), push, then re-arm the poll."
|
|
550
|
+
return 7
|
|
551
|
+
fi
|
|
552
|
+
return 0
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if [[ "$MODE" == step ]]; then
|
|
556
|
+
queue_gate
|
|
557
|
+
# The Phase 7 fences pass --fence: they decided to sync (expiry fallback, DIRTY-derived BEHIND, no merge_queue rule, a failed armed
|
|
558
|
+
# read) and made no extra read here. Any other caller gets the queue-armed refusal.
|
|
559
|
+
if [[ "$FENCE" != 1 ]]; then
|
|
560
|
+
step_guard
|
|
561
|
+
fi
|
|
562
|
+
rc=0; sync_step || rc=$?
|
|
563
|
+
exit "$rc"
|
|
564
|
+
fi
|
|
565
|
+
|
|
566
|
+
# Standalone: the PR number must name THIS branch, or the sync lands on the wrong PR.
|
|
567
|
+
rc=0; head_ref="$(gh pr view "$PR" --json headRefName --jq .headRefName 2>&1)" || rc=$?
|
|
568
|
+
if [[ "$rc" -ne 0 ]]; then tag gh "$rc" "gh pr view failed: $head_ref"; exit 4; fi
|
|
569
|
+
if [[ "$head_ref" != "$BRANCH" ]]; then
|
|
570
|
+
tag wrong_branch 12 "PR #$PR's head branch is '$head_ref' but this worktree is on '$BRANCH' — cd to that PR's worktree (or pass the right PR number); not syncing."
|
|
571
|
+
exit 12
|
|
572
|
+
fi
|
|
573
|
+
|
|
574
|
+
attempt=0
|
|
575
|
+
while [[ "$attempt" -lt "$MAX_ATTEMPTS" ]]; do
|
|
576
|
+
attempt=$((attempt + 1))
|
|
577
|
+
rc=0; state_line="$(gh pr view "$PR" --json state,mergeStateStatus \
|
|
578
|
+
--jq '"\(.state) \(.mergeStateStatus)"' 2>&1)" || rc=$?
|
|
579
|
+
if [[ "$rc" -ne 0 ]]; then tag gh "$rc" "gh pr view failed: $state_line"; exit 4; fi
|
|
580
|
+
|
|
581
|
+
tag state 0 "PR #$PR state: $state_line (branch: $BRANCH)"
|
|
582
|
+
|
|
583
|
+
if [[ "$state_line" == MERGED* || "$state_line" == CLOSED* ]]; then
|
|
584
|
+
tag closed 0 "PR is ${state_line%% *} — no sync needed"
|
|
585
|
+
exit 0
|
|
586
|
+
fi
|
|
587
|
+
|
|
588
|
+
if [[ "$state_line" != *BEHIND* && "$state_line" != *DIRTY* ]]; then
|
|
589
|
+
tag not_behind 0 "BEHIND unchanged: mergeStateStatus is not BEHIND — no sync needed"
|
|
590
|
+
exit 0
|
|
591
|
+
fi
|
|
592
|
+
|
|
593
|
+
# A queued PR is never synced (queue_gate exits kind=queued, or 4 on a failed read).
|
|
594
|
+
queue_gate
|
|
595
|
+
# An armed BEHIND PR on a merge-queue repo is not synced either (queue_wait_gate exits kind=queue_wait, or 4).
|
|
596
|
+
queue_wait_gate "$state_line"
|
|
597
|
+
|
|
598
|
+
tag behind 0 "BEHIND detected — auto-sync attempt ${attempt}/${MAX_ATTEMPTS}"
|
|
599
|
+
|
|
600
|
+
# GitHub DIRTY with a clean local merge-tree is the kb-index class: the server-side
|
|
601
|
+
# merge lacks the local driver. Key on merge-tree's exit code; on failure its stdout
|
|
602
|
+
# carries the real conflicted paths (no merge is in progress, so --diff-filter=U is
|
|
603
|
+
# empty). BEHIND needs no classification — sync_step's merge is the test.
|
|
604
|
+
if [[ "$state_line" == *DIRTY* ]]; then
|
|
605
|
+
rc=0; out="$(git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main 2>&1)" || rc=$?
|
|
606
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
607
|
+
tag fetch "$rc" "fetch origin main failed while classifying DIRTY"
|
|
608
|
+
exit 5
|
|
609
|
+
fi
|
|
610
|
+
rc=0; mt_out="$(git merge-tree --write-tree origin/main HEAD 2>&1)" || rc=$?
|
|
611
|
+
if [[ "$rc" -ne 0 ]]; then
|
|
612
|
+
# REGENERABLE-ARTIFACT CONFLICT (ADR-235): model.likec4.json is still committed, so
|
|
613
|
+
# it conflicts whenever two branches touch the .c4 sources. The resolver merges and
|
|
614
|
+
# regenerates it from the MERGED sources; it fails closed (touches nothing unless it
|
|
615
|
+
# committed) and never pushes. It ships beside this script; the target stays $PWD.
|
|
616
|
+
# After it commits, sync_step's merge is a no-op and HEAD != @{u}, so it pushes.
|
|
617
|
+
resolver="$(dirname "${BASH_SOURCE[0]}")/resolve-regenerable-conflicts.sh"
|
|
618
|
+
if [[ -f "$resolver" ]] && bash "$resolver" origin/main; then
|
|
619
|
+
tag regen_resolved 0 "regenerable conflict resolved — merge committed locally"
|
|
620
|
+
else
|
|
621
|
+
tag merge "$rc" "merge conflict — manual resolution required (merge-tree). Next: git merge origin/main, resolve, commit, push, then re-run. Conflicted paths:"
|
|
622
|
+
printf '%s\n' "$mt_out" | grep '^CONFLICT ' || true
|
|
623
|
+
exit 6
|
|
624
|
+
fi
|
|
625
|
+
fi
|
|
626
|
+
fi
|
|
627
|
+
|
|
628
|
+
rc=0; sync_step || rc=$?
|
|
629
|
+
# 11 (noop) exits too: re-reading state here would see the same lagging BEHIND and
|
|
630
|
+
# burn the remaining attempts on no-ops. The caller re-runs once GitHub catches up.
|
|
631
|
+
if [[ "$rc" -ne 0 ]]; then exit "$rc"; fi
|
|
632
|
+
|
|
633
|
+
tag pushed 0 "auto-sync ${attempt} pushed — CI will re-run on new SHA"
|
|
634
|
+
|
|
635
|
+
rc=0; state_line="$(gh pr view "$PR" --json state,mergeStateStatus \
|
|
636
|
+
--jq '"\(.state) \(.mergeStateStatus)"' 2>&1)" || rc=$?
|
|
637
|
+
if [[ "$rc" -ne 0 ]]; then tag gh "$rc" "post-push gh pr view failed: $state_line"; exit 4; fi
|
|
638
|
+
tag state 0 "post-sync state: $state_line"
|
|
639
|
+
|
|
640
|
+
if [[ "$state_line" != *BEHIND* ]]; then
|
|
641
|
+
tag resolved 0 "BEHIND resolved: branch caught up to main"
|
|
642
|
+
exit 0
|
|
643
|
+
fi
|
|
644
|
+
done
|
|
645
|
+
|
|
646
|
+
tag exhausted 8 "BEHIND still present after ${MAX_ATTEMPTS} sync(s) — main may be moving faster than CI"
|
|
647
|
+
exit 8
|