@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.
Files changed (832) hide show
  1. package/.claude-plugin/agents.manifest.json +476 -0
  2. package/.claude-plugin/plugin.json +42 -0
  3. package/README.md +44 -2
  4. package/agents/community/.gitkeep +0 -0
  5. package/agents/engineering/cto.md +87 -0
  6. package/agents/engineering/design/ddd-architect.md +95 -0
  7. package/agents/engineering/discovery/agent-finder.md +214 -0
  8. package/agents/engineering/discovery/functional-discovery.md +182 -0
  9. package/agents/engineering/infra/infra-security.md +151 -0
  10. package/agents/engineering/infra/platform-strategist.md +109 -0
  11. package/agents/engineering/infra/terraform-architect.md +171 -0
  12. package/agents/engineering/prompt-engineer.md +37 -0
  13. package/agents/engineering/research/best-practices-researcher.md +115 -0
  14. package/agents/engineering/research/framework-docs-researcher.md +93 -0
  15. package/agents/engineering/research/git-history-analyzer.md +53 -0
  16. package/agents/engineering/research/learnings-researcher.md +285 -0
  17. package/agents/engineering/research/repo-research-analyst.md +118 -0
  18. package/agents/engineering/review/agent-native-reviewer.md +279 -0
  19. package/agents/engineering/review/architecture-strategist.md +61 -0
  20. package/agents/engineering/review/code-quality-analyst.md +92 -0
  21. package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
  22. package/agents/engineering/review/data-integrity-guardian.md +82 -0
  23. package/agents/engineering/review/data-migration-expert.md +98 -0
  24. package/agents/engineering/review/deployment-verification-agent.md +183 -0
  25. package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
  26. package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
  27. package/agents/engineering/review/legacy-code-expert.md +55 -0
  28. package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
  29. package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
  30. package/agents/engineering/review/performance-oracle.md +130 -0
  31. package/agents/engineering/review/security-sentinel.md +167 -0
  32. package/agents/engineering/review/semgrep-sast.md +36 -0
  33. package/agents/engineering/review/test-design-reviewer.md +150 -0
  34. package/agents/engineering/review/user-impact-reviewer.md +70 -0
  35. package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
  36. package/agents/finance/budget-analyst.md +29 -0
  37. package/agents/finance/cfo.md +44 -0
  38. package/agents/finance/financial-reporter.md +30 -0
  39. package/agents/finance/revenue-analyst.md +30 -0
  40. package/agents/legal/clo.md +115 -0
  41. package/agents/legal/legal-compliance-auditor.md +110 -0
  42. package/agents/legal/legal-document-generator.md +134 -0
  43. package/agents/marketing/analytics-analyst.md +25 -0
  44. package/agents/marketing/brand-architect.md +181 -0
  45. package/agents/marketing/cmo.md +76 -0
  46. package/agents/marketing/conversion-optimizer.md +19 -0
  47. package/agents/marketing/copywriter.md +20 -0
  48. package/agents/marketing/fact-checker.md +70 -0
  49. package/agents/marketing/growth-strategist.md +145 -0
  50. package/agents/marketing/paid-media-strategist.md +28 -0
  51. package/agents/marketing/pricing-strategist.md +17 -0
  52. package/agents/marketing/programmatic-seo-specialist.md +25 -0
  53. package/agents/marketing/retention-strategist.md +23 -0
  54. package/agents/marketing/seo-aeo-analyst.md +164 -0
  55. package/agents/operations/coo.md +50 -0
  56. package/agents/operations/ops-advisor.md +78 -0
  57. package/agents/operations/ops-provisioner.md +101 -0
  58. package/agents/operations/ops-research.md +52 -0
  59. package/agents/operations/service-automator.md +278 -0
  60. package/agents/product/business-validator.md +206 -0
  61. package/agents/product/competitive-intelligence.md +89 -0
  62. package/agents/product/cpo.md +63 -0
  63. package/agents/product/design/ux-design-lead.md +209 -0
  64. package/agents/product/spec-flow-analyzer.md +122 -0
  65. package/agents/sales/cro.md +44 -0
  66. package/agents/sales/deal-architect.md +29 -0
  67. package/agents/sales/outbound-strategist.md +29 -0
  68. package/agents/sales/pipeline-analyst.md +29 -0
  69. package/agents/support/cco.md +48 -0
  70. package/agents/support/community-manager.md +570 -0
  71. package/agents/support/ticket-triage.md +70 -0
  72. package/bin/soleur-opencode.js +29 -0
  73. package/commands/go.md +660 -0
  74. package/commands/help.md +273 -0
  75. package/commands/sync.md +977 -0
  76. package/commands/version.md +103 -0
  77. package/hooks/antigravity-hooks.json +84 -0
  78. package/hooks/antigravity-session-start.sh +15 -0
  79. package/hooks/bare-root-cwd-guard.sh +131 -0
  80. package/hooks/browser-snapshot-credential-guard.sh +200 -0
  81. package/hooks/codex-session-start.sh +9 -0
  82. package/hooks/compaction-state.sh +525 -0
  83. package/hooks/destructive-command-guard.sh +1387 -0
  84. package/hooks/devin-session-start.sh +90 -0
  85. package/hooks/ext-filter-detect.sh +171 -0
  86. package/hooks/hooks.json +133 -0
  87. package/hooks/lib/hook-tool-kind.sh +24 -0
  88. package/hooks/lib/log-rotation.sh +176 -0
  89. package/hooks/lib/shell-argv.pl +576 -0
  90. package/hooks/memory-backstop.sh +1114 -0
  91. package/hooks/operator-stage-approval.sh +391 -0
  92. package/hooks/stop-hook.sh +367 -0
  93. package/hooks/unkept-promise-hook.sh +383 -0
  94. package/hooks/version-banner.sh +127 -0
  95. package/hooks/welcome-hook.sh +50 -0
  96. package/install.js +29 -0
  97. package/lib/agent-registry.ts +154 -0
  98. package/lib/c4-canonical-cli.mjs +34 -0
  99. package/lib/c4-canonical.mjs +46 -0
  100. package/lib/c4-from-components.ts +554 -0
  101. package/lib/go-routing.ts +81 -0
  102. package/lib/grok-inspect-contract.ts +311 -0
  103. package/lib/harness-model-map.ts +101 -0
  104. package/lib/harness-parity.ts +726 -0
  105. package/lib/harness-tool-map.ts +180 -0
  106. package/lib/harness.ts +716 -0
  107. package/lib/heartbeat-live-reconcile.ts +1153 -0
  108. package/lib/heartbeat-manifest.ts +361 -0
  109. package/lib/kb-coverage.ts +252 -0
  110. package/lib/pr-merge-poll.ts +103 -0
  111. package/lib/workflow-fidelity.ts +388 -0
  112. package/opencode/INSTRUCTIONS.md +171 -0
  113. package/opencode/agents/engineering/cto.md +10 -0
  114. package/opencode/agents/engineering/design/ddd-architect.md +10 -0
  115. package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
  116. package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
  117. package/opencode/agents/engineering/infra/infra-security.md +10 -0
  118. package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
  119. package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
  120. package/opencode/agents/engineering/prompt-engineer.md +10 -0
  121. package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
  122. package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
  123. package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
  124. package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
  125. package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
  126. package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
  127. package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
  128. package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
  129. package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
  130. package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
  131. package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
  132. package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
  133. package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
  134. package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
  135. package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
  136. package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
  137. package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
  138. package/opencode/agents/engineering/review/performance-oracle.md +10 -0
  139. package/opencode/agents/engineering/review/security-sentinel.md +10 -0
  140. package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
  141. package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
  142. package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
  143. package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
  144. package/opencode/agents/finance/budget-analyst.md +10 -0
  145. package/opencode/agents/finance/cfo.md +10 -0
  146. package/opencode/agents/finance/financial-reporter.md +10 -0
  147. package/opencode/agents/finance/revenue-analyst.md +10 -0
  148. package/opencode/agents/legal/clo.md +10 -0
  149. package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
  150. package/opencode/agents/legal/legal-document-generator.md +10 -0
  151. package/opencode/agents/marketing/analytics-analyst.md +10 -0
  152. package/opencode/agents/marketing/brand-architect.md +10 -0
  153. package/opencode/agents/marketing/cmo.md +10 -0
  154. package/opencode/agents/marketing/conversion-optimizer.md +10 -0
  155. package/opencode/agents/marketing/copywriter.md +10 -0
  156. package/opencode/agents/marketing/fact-checker.md +10 -0
  157. package/opencode/agents/marketing/growth-strategist.md +10 -0
  158. package/opencode/agents/marketing/paid-media-strategist.md +10 -0
  159. package/opencode/agents/marketing/pricing-strategist.md +10 -0
  160. package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
  161. package/opencode/agents/marketing/retention-strategist.md +10 -0
  162. package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
  163. package/opencode/agents/operations/coo.md +10 -0
  164. package/opencode/agents/operations/ops-advisor.md +10 -0
  165. package/opencode/agents/operations/ops-provisioner.md +10 -0
  166. package/opencode/agents/operations/ops-research.md +10 -0
  167. package/opencode/agents/operations/service-automator.md +10 -0
  168. package/opencode/agents/product/business-validator.md +10 -0
  169. package/opencode/agents/product/competitive-intelligence.md +10 -0
  170. package/opencode/agents/product/cpo.md +10 -0
  171. package/opencode/agents/product/design/ux-design-lead.md +10 -0
  172. package/opencode/agents/product/spec-flow-analyzer.md +10 -0
  173. package/opencode/agents/sales/cro.md +10 -0
  174. package/opencode/agents/sales/deal-architect.md +10 -0
  175. package/opencode/agents/sales/outbound-strategist.md +10 -0
  176. package/opencode/agents/sales/pipeline-analyst.md +10 -0
  177. package/opencode/agents/support/cco.md +10 -0
  178. package/opencode/agents/support/community-manager.md +10 -0
  179. package/opencode/agents/support/ticket-triage.md +10 -0
  180. package/opencode/commands/go.md +10 -0
  181. package/opencode/commands/help.md +10 -0
  182. package/opencode/commands/sync.md +10 -0
  183. package/opencode/commands/version.md +11 -0
  184. package/opencode/opencode.json +8 -0
  185. package/opencode/plugin.ts +818 -0
  186. package/package.json +36 -4
  187. package/scripts/admin-merge-ready.sh +545 -0
  188. package/scripts/admin-merge-ready.test.sh +753 -0
  189. package/scripts/affected-tests.sh +908 -0
  190. package/scripts/affected-tests.test.sh +1797 -0
  191. package/scripts/alpha-metrics.sh +78 -0
  192. package/scripts/alpha-metrics.test.sh +115 -0
  193. package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
  194. package/scripts/audit-flag-flip.sh +107 -0
  195. package/scripts/check-red-on-main.sh +316 -0
  196. package/scripts/ci-head-verdict.sh +411 -0
  197. package/scripts/cloud-detect.sh +193 -0
  198. package/scripts/delegation-verify.sh +657 -0
  199. package/scripts/delegation-verify.test.sh +1424 -0
  200. package/scripts/deploy-arm.sh +475 -0
  201. package/scripts/domain-model-drift.sh +419 -0
  202. package/scripts/emit-decision.sh +144 -0
  203. package/scripts/emit-decision.test.sh +144 -0
  204. package/scripts/ext-filter-divergence-corpus.txt +15 -0
  205. package/scripts/ext-filter-divergence.sh +189 -0
  206. package/scripts/generate-c4-from-components.ts +442 -0
  207. package/scripts/grok-fidelity-gate.sh +68 -0
  208. package/scripts/grok-pre-push-gate.sh +232 -0
  209. package/scripts/harness-discovery-smoke.ts +906 -0
  210. package/scripts/harness-parity-census.ts +92 -0
  211. package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
  212. package/scripts/install-opencode-adapter.ts +509 -0
  213. package/scripts/lib/affected-tests/common.sh +365 -0
  214. package/scripts/lib/affected-tests/go.sh +157 -0
  215. package/scripts/lib/affected-tests/js.sh +188 -0
  216. package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
  217. package/scripts/lib/affected-tests/python.sh +185 -0
  218. package/scripts/lib/context-sanitize.sh +49 -0
  219. package/scripts/lib/domain-model-lib.sh +180 -0
  220. package/scripts/lib/ext-filter-grammar.tsv +34 -0
  221. package/scripts/lib/operator-script.sh +1236 -0
  222. package/scripts/lib/proc.sh +580 -0
  223. package/scripts/lib/session-state.sh +748 -0
  224. package/scripts/lib/tmp-classify.sh +843 -0
  225. package/scripts/lib/wrapper-boundary.sh +47 -0
  226. package/scripts/lint-ratchet.py +1547 -0
  227. package/scripts/monitor-pr-checks.sh +441 -0
  228. package/scripts/pipeline-tally.sh +756 -0
  229. package/scripts/pipeline-tally.test.sh +740 -0
  230. package/scripts/plugin-version.sh +528 -0
  231. package/scripts/precommit-guard.sh +115 -0
  232. package/scripts/precommit-guard.test.sh +254 -0
  233. package/scripts/reconcile-live-heartbeats.ts +705 -0
  234. package/scripts/render-c4-model.sh +217 -0
  235. package/scripts/resolve-git-root.sh +55 -0
  236. package/scripts/resolve-regenerable-conflicts.sh +363 -0
  237. package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
  238. package/scripts/ruff-requirements.txt +22 -0
  239. package/scripts/run-in-pid-namespace.sh +98 -0
  240. package/scripts/run-in-pid-namespace.test.sh +290 -0
  241. package/scripts/scan-ancestor-signal-helpers.py +556 -0
  242. package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
  243. package/scripts/setup-ralph-loop.sh +238 -0
  244. package/scripts/sync-cursor-name-map.ts +316 -0
  245. package/scripts/sync-grok-agent-compat.ts +188 -0
  246. package/scripts/sync-npm-package.ts +165 -0
  247. package/scripts/sync-opencode-adapter.ts +498 -0
  248. package/scripts/sync-pr-behind.sh +647 -0
  249. package/scripts/sync-pr-behind.test.sh +252 -0
  250. package/scripts/taste-profile-update.sh +180 -0
  251. package/scripts/taste-profile-update.test.sh +167 -0
  252. package/scripts/write-budget-marker.sh +23 -0
  253. package/scripts/write-kb-coverage.ts +113 -0
  254. package/skills/admin-ip-refresh/SKILL.md +81 -0
  255. package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
  256. package/skills/agent-browser/SKILL.md +698 -0
  257. package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
  258. package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
  259. package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
  260. package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
  261. package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
  262. package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
  263. package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
  264. package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
  265. package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
  266. package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
  267. package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
  268. package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
  269. package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
  270. package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
  271. package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
  272. package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
  273. package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
  274. package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
  275. package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
  276. package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
  277. package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
  278. package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
  279. package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
  280. package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
  281. package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
  282. package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
  283. package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
  284. package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
  285. package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
  286. package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
  287. package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
  288. package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
  289. package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
  290. package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
  291. package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
  292. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
  293. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
  294. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
  295. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
  296. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
  297. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
  298. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
  299. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
  300. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
  301. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
  302. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
  303. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
  304. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
  305. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
  306. package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
  307. package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
  308. package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
  309. package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
  310. package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
  311. package/skills/agent-native-architecture/SKILL.md +479 -0
  312. package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
  313. package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
  314. package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
  315. package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
  316. package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
  317. package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
  318. package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
  319. package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
  320. package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
  321. package/skills/agent-native-architecture/references/product-implications.md +478 -0
  322. package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
  323. package/skills/agent-native-architecture/references/self-modification.md +294 -0
  324. package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
  325. package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
  326. package/skills/agent-native-audit/SKILL.md +300 -0
  327. package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
  328. package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
  329. package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
  330. package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
  331. package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
  332. package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
  333. package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
  334. package/skills/architecture/SKILL.md +436 -0
  335. package/skills/architecture/references/adr-template.md +154 -0
  336. package/skills/architecture/references/likec4-reference.md +136 -0
  337. package/skills/architecture/references/nfr-reference.md +126 -0
  338. package/skills/archive-kb/SKILL.md +86 -0
  339. package/skills/archive-kb/scripts/archive-kb.sh +300 -0
  340. package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
  341. package/skills/atdd-developer/SKILL.md +65 -0
  342. package/skills/brainstorm/SKILL.md +701 -0
  343. package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
  344. package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
  345. package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
  346. package/skills/brainstorm/references/ui-surface-terms.md +42 -0
  347. package/skills/brainstorm-techniques/SKILL.md +231 -0
  348. package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
  349. package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
  350. package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
  351. package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
  352. package/skills/campaign-calendar/SKILL.md +145 -0
  353. package/skills/cf-token-scope/SKILL.md +164 -0
  354. package/skills/cf-token-scope/references/widen-playbook.md +114 -0
  355. package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
  356. package/skills/changelog/SKILL.md +142 -0
  357. package/skills/code-to-prd/SKILL.md +66 -0
  358. package/skills/code-to-prd/references/banner-template.md +12 -0
  359. package/skills/code-to-prd/references/prd-template.md +41 -0
  360. package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
  361. package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
  362. package/skills/code-to-prd/test/fixture/.env.example +7 -0
  363. package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
  364. package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
  365. package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
  366. package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
  367. package/skills/code-to-prd/test/fixture/package.json +6 -0
  368. package/skills/cohort-status/SKILL.md +62 -0
  369. package/skills/community/SKILL.md +210 -0
  370. package/skills/community/scripts/bsky-community.sh +644 -0
  371. package/skills/community/scripts/bsky-setup.sh +631 -0
  372. package/skills/community/scripts/community-router.sh +93 -0
  373. package/skills/community/scripts/discord-community.sh +487 -0
  374. package/skills/community/scripts/discord-setup.sh +784 -0
  375. package/skills/community/scripts/github-community.sh +706 -0
  376. package/skills/community/scripts/hn-community.sh +233 -0
  377. package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
  378. package/skills/community/scripts/linkedin-community.sh +750 -0
  379. package/skills/community/scripts/linkedin-setup.sh +758 -0
  380. package/skills/community/scripts/x-community.sh +890 -0
  381. package/skills/community/scripts/x-setup.sh +713 -0
  382. package/skills/community/test/community-argv.test.sh +2922 -0
  383. package/skills/community/test/github-community.test.sh +981 -0
  384. package/skills/competitive-analysis/SKILL.md +69 -0
  385. package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
  386. package/skills/compound/SKILL.md +673 -0
  387. package/skills/compound/scripts/token-efficiency-report.sh +334 -0
  388. package/skills/compound/test/phase-16.test.sh +379 -0
  389. package/skills/compound-capture/SKILL.md +791 -0
  390. package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
  391. package/skills/compound-capture/assets/resolution-template.md +116 -0
  392. package/skills/compound-capture/references/yaml-schema.md +67 -0
  393. package/skills/compound-capture/schema.yaml +181 -0
  394. package/skills/constraint-scaffold/SKILL.md +175 -0
  395. package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
  396. package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
  397. package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
  398. package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
  399. package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
  400. package/skills/constraint-scaffold/references/shared-runner.template +135 -0
  401. package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
  402. package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
  403. package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
  404. package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
  405. package/skills/constraint-scaffold/test/generator.test.sh +93 -0
  406. package/skills/constraint-scaffold/test/parity.test.sh +285 -0
  407. package/skills/content-writer/SKILL.md +242 -0
  408. package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
  409. package/skills/cron-delete/SKILL.md +56 -0
  410. package/skills/cron-list/SKILL.md +54 -0
  411. package/skills/deepen-plan/SKILL.md +937 -0
  412. package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
  413. package/skills/deploy/SKILL.md +115 -0
  414. package/skills/deploy/references/hetzner-setup.md +67 -0
  415. package/skills/deploy/scripts/deploy.sh +37 -0
  416. package/skills/deploy-docs/SKILL.md +95 -0
  417. package/skills/dhh-rails-style/SKILL.md +203 -0
  418. package/skills/dhh-rails-style/references/architecture.md +717 -0
  419. package/skills/dhh-rails-style/references/controllers.md +323 -0
  420. package/skills/dhh-rails-style/references/frontend.md +556 -0
  421. package/skills/dhh-rails-style/references/gems.md +316 -0
  422. package/skills/dhh-rails-style/references/models.md +388 -0
  423. package/skills/dhh-rails-style/references/testing.md +354 -0
  424. package/skills/discord-content/SKILL.md +126 -0
  425. package/skills/docs-site/SKILL.md +214 -0
  426. package/skills/drain-labeled-backlog/SKILL.md +203 -0
  427. package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
  428. package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
  429. package/skills/drain-prs/SKILL.md +143 -0
  430. package/skills/drain-prs/scripts/triage-prs.sh +192 -0
  431. package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
  432. package/skills/dspy-ruby/SKILL.md +634 -0
  433. package/skills/dspy-ruby/assets/config-template.rb +359 -0
  434. package/skills/dspy-ruby/assets/module-template.rb +326 -0
  435. package/skills/dspy-ruby/assets/signature-template.rb +143 -0
  436. package/skills/dspy-ruby/references/core-concepts.md +268 -0
  437. package/skills/dspy-ruby/references/optimization.md +623 -0
  438. package/skills/dspy-ruby/references/providers.md +335 -0
  439. package/skills/eval-harness/README.md +194 -0
  440. package/skills/eval-harness/SKILL.md +157 -0
  441. package/skills/eval-harness/enums/go-routes.json +13 -0
  442. package/skills/eval-harness/enums/incident-threshold.json +5 -0
  443. package/skills/eval-harness/enums/lane.json +5 -0
  444. package/skills/eval-harness/enums/tool-selection.json +20 -0
  445. package/skills/eval-harness/enums/triage-levels.json +5 -0
  446. package/skills/eval-harness/gated-skills.json +34 -0
  447. package/skills/eval-harness/models.generated.json +5 -0
  448. package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
  449. package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
  450. package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
  451. package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
  452. package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
  453. package/skills/eval-harness/prompts/go-baseline.txt +6 -0
  454. package/skills/eval-harness/prompts/go-skill.txt +21 -0
  455. package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
  456. package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
  457. package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
  458. package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
  459. package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
  460. package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
  461. package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
  462. package/skills/eval-harness/prompts/triage-skill.txt +10 -0
  463. package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
  464. package/skills/eval-harness/scripts/extract-block.cjs +87 -0
  465. package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
  466. package/skills/eval-harness/scripts/gen-models.sh +41 -0
  467. package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
  468. package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
  469. package/skills/eval-harness/scripts/parse-label.cjs +93 -0
  470. package/skills/eval-harness/scripts/verdict.cjs +132 -0
  471. package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
  472. package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
  473. package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
  474. package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
  475. package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
  476. package/skills/eval-harness/test/eval-gate.test.sh +132 -0
  477. package/skills/eval-harness/test/extract-block.test.sh +87 -0
  478. package/skills/eval-harness/test/gate-classification.test.sh +77 -0
  479. package/skills/eval-harness/test/gen-models.test.sh +75 -0
  480. package/skills/eval-harness/test/measure-classification.test.sh +74 -0
  481. package/skills/eval-harness/test/parse-label.test.sh +129 -0
  482. package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
  483. package/skills/eval-harness/test/verdict.test.sh +123 -0
  484. package/skills/every-style-editor/SKILL.md +142 -0
  485. package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
  486. package/skills/feature-tweet/SKILL.md +199 -0
  487. package/skills/feature-video/SKILL.md +412 -0
  488. package/skills/feature-video/scripts/check_deps.sh +281 -0
  489. package/skills/file-todos/SKILL.md +267 -0
  490. package/skills/file-todos/assets/todo-template.md +166 -0
  491. package/skills/fix-issue/SKILL.md +278 -0
  492. package/skills/fix-issue/references/agent-authored-exclusion.md +120 -0
  493. package/skills/fix-issue/references/exclude-label-jq-snippet.md +97 -0
  494. package/skills/flag-bootstrap/SETUP.md +142 -0
  495. package/skills/flag-create/SKILL.md +145 -0
  496. package/skills/flag-create/scripts/create.sh +273 -0
  497. package/skills/flag-delete/SKILL.md +167 -0
  498. package/skills/flag-delete/scripts/delete.sh +288 -0
  499. package/skills/flag-list/SKILL.md +99 -0
  500. package/skills/flag-list/scripts/list.sh +275 -0
  501. package/skills/flag-set-role/SKILL.md +229 -0
  502. package/skills/flag-set-role/scripts/flip.sh +774 -0
  503. package/skills/frontend-anti-slop/SKILL.md +106 -0
  504. package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
  505. package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
  506. package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
  507. package/skills/frontend-design/SKILL.md +77 -0
  508. package/skills/gdpr-gate/NOTICE +136 -0
  509. package/skills/gdpr-gate/SKILL.md +341 -0
  510. package/skills/gdpr-gate/references/fields.md +160 -0
  511. package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
  512. package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
  513. package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
  514. package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
  515. package/skills/gdpr-gate/references/layers/frontend.md +249 -0
  516. package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
  517. package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
  518. package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
  519. package/skills/gdpr-gate/references/legal-consent.md +140 -0
  520. package/skills/gdpr-gate/references/non-negotiables.md +60 -0
  521. package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
  522. package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
  523. package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
  524. package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
  525. package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
  526. package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
  527. package/skills/gemini-imagegen/SKILL.md +283 -0
  528. package/skills/gemini-imagegen/requirements.txt +5 -0
  529. package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
  530. package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
  531. package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
  532. package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
  533. package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
  534. package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
  535. package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
  536. package/skills/git-worktree/SKILL.md +534 -0
  537. package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
  538. package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
  539. package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
  540. package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
  541. package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
  542. package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
  543. package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
  544. package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
  545. package/skills/go/SKILL.md +54 -0
  546. package/skills/growth/SKILL.md +164 -0
  547. package/skills/harvest-debt/SKILL.md +78 -0
  548. package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
  549. package/skills/heal-skill/SKILL.md +173 -0
  550. package/skills/help/SKILL.md +46 -0
  551. package/skills/incident/NOTICE +39 -0
  552. package/skills/incident/SKILL.md +395 -0
  553. package/skills/incident/scripts/dry-run.sh +448 -0
  554. package/skills/incident/scripts/redact-engine.py +412 -0
  555. package/skills/incident/scripts/redact-sentinel.sh +44 -0
  556. package/skills/incident/templates/pir.md +139 -0
  557. package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
  558. package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
  559. package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
  560. package/skills/incident/test/fixtures/positive-corpus.md +87 -0
  561. package/skills/incident/test/redact-sentinel.test.sh +1420 -0
  562. package/skills/invoice/SKILL.md +206 -0
  563. package/skills/kb-glossary/SKILL.md +71 -0
  564. package/skills/kb-glossary/references/glossary-format.md +111 -0
  565. package/skills/kb-glossary/references/rejected-request-register.md +115 -0
  566. package/skills/kb-search/SKILL.md +276 -0
  567. package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
  568. package/skills/legal-audit/SKILL.md +161 -0
  569. package/skills/legal-generate/NOTICE +242 -0
  570. package/skills/legal-generate/SKILL.md +244 -0
  571. package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
  572. package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
  573. package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
  574. package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
  575. package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
  576. package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
  577. package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
  578. package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
  579. package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
  580. package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
  581. package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
  582. package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
  583. package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
  584. package/skills/linear-fetch/SKILL.md +247 -0
  585. package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
  586. package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
  587. package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
  588. package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
  589. package/skills/linear-fetch/test/parity.test.sh +112 -0
  590. package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
  591. package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
  592. package/skills/merge-pr/SKILL.md +670 -0
  593. package/skills/model-launch-review/SKILL.md +255 -0
  594. package/skills/model-launch-review/scripts/audit-models.sh +501 -0
  595. package/skills/one-shot/SKILL.md +316 -0
  596. package/skills/one-shot/references/token-discipline.md +74 -0
  597. package/skills/operator-bootstrap/SKILL.md +412 -0
  598. package/skills/operator-bootstrap/template.sh +439 -0
  599. package/skills/operator-digest/SKILL.md +287 -0
  600. package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
  601. package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
  602. package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
  603. package/skills/operator-rephrase/SKILL.md +98 -0
  604. package/skills/pencil-setup/SKILL.md +201 -0
  605. package/skills/pencil-setup/scripts/check_deps.sh +556 -0
  606. package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
  607. package/skills/pencil-setup/scripts/package-lock.json +1172 -0
  608. package/skills/pencil-setup/scripts/package.json +14 -0
  609. package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
  610. package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
  611. package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
  612. package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
  613. package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
  614. package/skills/plan/SKILL.md +1140 -0
  615. package/skills/plan/references/differential-migration-testing.md +185 -0
  616. package/skills/plan/references/plan-community-discovery.md +42 -0
  617. package/skills/plan/references/plan-founder-check.md +137 -0
  618. package/skills/plan/references/plan-functional-overlap.md +25 -0
  619. package/skills/plan/references/plan-host-fanout.md +51 -0
  620. package/skills/plan/references/plan-issue-templates.md +779 -0
  621. package/skills/plan/references/plan-network-outage-checklist.md +131 -0
  622. package/skills/plan/references/plan-scope-check.md +126 -0
  623. package/skills/plan/references/plan-sharp-edges.md +331 -0
  624. package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
  625. package/skills/plan/references/webapp-cwv-observability.md +143 -0
  626. package/skills/plan-review/SKILL.md +91 -0
  627. package/skills/plan-review/lib/named-panel.mjs +58 -0
  628. package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
  629. package/skills/postmerge/SKILL.md +642 -0
  630. package/skills/postmerge/references/deploy-status-debugging.md +141 -0
  631. package/skills/postmerge/references/graceful-degradation.md +20 -0
  632. package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
  633. package/skills/preflight/SKILL.md +1553 -0
  634. package/skills/preflight/references/check-13-founder-check.md +286 -0
  635. package/skills/preflight/scripts/founder-check.py +1640 -0
  636. package/skills/preflight/scripts/parse-form-a.awk +107 -0
  637. package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
  638. package/skills/product-roadmap/SKILL.md +357 -0
  639. package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
  640. package/skills/provision-cloudflare/SKILL.md +67 -0
  641. package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
  642. package/skills/provision-doppler/SKILL.md +58 -0
  643. package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
  644. package/skills/provision-github/SKILL.md +59 -0
  645. package/skills/provision-github/scripts/provision-github.sh +300 -0
  646. package/skills/provision-hetzner/SKILL.md +76 -0
  647. package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
  648. package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
  649. package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
  650. package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
  651. package/skills/qa/SKILL.md +263 -0
  652. package/skills/qa/references/browser-preflight.md +22 -0
  653. package/skills/questionnaire-generate/SKILL.md +328 -0
  654. package/skills/questionnaire-generate/references/questionnaire.template +60 -0
  655. package/skills/rclone/SKILL.md +162 -0
  656. package/skills/rclone/scripts/check_setup.sh +63 -0
  657. package/skills/release-announce/SKILL.md +65 -0
  658. package/skills/release-docs/SKILL.md +92 -0
  659. package/skills/reproduce-bug/SKILL.md +358 -0
  660. package/skills/resolve-debt/SKILL.md +85 -0
  661. package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
  662. package/skills/resolve-parallel/SKILL.md +45 -0
  663. package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
  664. package/skills/resolve-pr-parallel/SKILL.md +68 -0
  665. package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
  666. package/skills/resolve-todo-parallel/SKILL.md +57 -0
  667. package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
  668. package/skills/review/SKILL.md +1620 -0
  669. package/skills/review/references/anti-slop-scanner-hook.md +40 -0
  670. package/skills/review/references/defect-classes-migrations.md +9 -0
  671. package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
  672. package/skills/review/references/review-e2e-testing.md +116 -0
  673. package/skills/review/references/review-evidence-comment.md +36 -0
  674. package/skills/review/references/review-todo-structure.md +165 -0
  675. package/skills/review/references/risk-tier-and-fix-rounds.md +97 -0
  676. package/skills/review/references/semgrep-custom-rules.yaml +174 -0
  677. package/skills/review/references/ultrathink-phases.md +98 -0
  678. package/skills/review/references/wfs.md +6 -0
  679. package/skills/review/scripts/emit-review-trailer.sh +499 -0
  680. package/skills/review/scripts/ensure-semgrep.sh +99 -0
  681. package/skills/review/scripts/fix-round-seats.sh +197 -0
  682. package/skills/review/test/emit-review-trailer.test.sh +387 -0
  683. package/skills/review/test/ensure-semgrep.test.sh +111 -0
  684. package/skills/review/test/fix-round-seats.test.sh +237 -0
  685. package/skills/review/workflows/README.md +147 -0
  686. package/skills/review/workflows/review.workflow.js +667 -0
  687. package/skills/schedule/SKILL.md +796 -0
  688. package/skills/seo-aeo/SKILL.md +139 -0
  689. package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
  690. package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
  691. package/skills/ship/SKILL.md +3023 -0
  692. package/skills/ship/references/adr-ordinal-collision.md +47 -0
  693. package/skills/ship/references/affected-gate-contract.md +115 -0
  694. package/skills/ship/references/ci-run-diagnosis.md +29 -0
  695. package/skills/ship/references/ci-workflow-authoring.md +68 -0
  696. package/skills/ship/references/cleanup-merged-archival.md +39 -0
  697. package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
  698. package/skills/ship/references/cto-ruling-armed-push.md +5 -0
  699. package/skills/ship/references/decision-challenges-render.md +71 -0
  700. package/skills/ship/references/delegated-act-authoring-form.md +7 -0
  701. package/skills/ship/references/detached-battery-verdict.md +13 -0
  702. package/skills/ship/references/epic-close-sweep.md +62 -0
  703. package/skills/ship/references/feature-tweet-draft.md +42 -0
  704. package/skills/ship/references/followthrough-issue-body-template.md +47 -0
  705. package/skills/ship/references/followthrough-stub-template.sh +92 -0
  706. package/skills/ship/references/merge-queue-dequeue.md +39 -0
  707. package/skills/ship/references/operator-holds.md +179 -0
  708. package/skills/ship/references/pipeline-tally-render.md +43 -0
  709. package/skills/ship/references/pr-overlap.md +153 -0
  710. package/skills/ship/references/queue-mode.md +7 -0
  711. package/skills/ship/references/ready-run-wait.md +36 -0
  712. package/skills/ship/references/red-on-main-quarantine.md +110 -0
  713. package/skills/ship/references/register-update-pr-pattern.md +88 -0
  714. package/skills/ship/references/settle-then-admin-merge.md +130 -0
  715. package/skills/ship/references/supabase-column-probe.md +13 -0
  716. package/skills/ship/scripts/auto-close-scan.sh +76 -0
  717. package/skills/ship/scripts/battery-owed.sh +403 -0
  718. package/skills/ship/scripts/hold-gate-eval.sh +410 -0
  719. package/skills/ship/scripts/net-issue-flow.sh +665 -0
  720. package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
  721. package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
  722. package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
  723. package/skills/skill-creator/SKILL.md +299 -0
  724. package/skills/skill-creator/references/api-security.md +248 -0
  725. package/skills/skill-creator/references/authoring-levers.md +110 -0
  726. package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
  727. package/skills/skill-creator/references/best-practices.md +431 -0
  728. package/skills/skill-creator/references/common-patterns.md +639 -0
  729. package/skills/skill-creator/references/core-principles.md +193 -0
  730. package/skills/skill-creator/references/executable-code.md +188 -0
  731. package/skills/skill-creator/references/iteration-and-testing.md +509 -0
  732. package/skills/skill-creator/references/official-spec.md +193 -0
  733. package/skills/skill-creator/references/recommended-structure.md +180 -0
  734. package/skills/skill-creator/references/skill-structure.md +396 -0
  735. package/skills/skill-creator/references/using-scripts.md +122 -0
  736. package/skills/skill-creator/references/using-templates.md +120 -0
  737. package/skills/skill-creator/references/workflows-and-validation.md +541 -0
  738. package/skills/skill-creator/scripts/init_skill.py +322 -0
  739. package/skills/skill-creator/scripts/package_skill.py +110 -0
  740. package/skills/skill-creator/scripts/quick_validate.py +64 -0
  741. package/skills/skill-creator/templates/router-skill.md +73 -0
  742. package/skills/skill-creator/templates/simple-skill.md +34 -0
  743. package/skills/skill-creator/workflows/add-reference.md +96 -0
  744. package/skills/skill-creator/workflows/add-script.md +104 -0
  745. package/skills/skill-creator/workflows/add-template.md +83 -0
  746. package/skills/skill-creator/workflows/add-workflow.md +128 -0
  747. package/skills/skill-creator/workflows/audit-skill.md +159 -0
  748. package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
  749. package/skills/skill-creator/workflows/create-new-skill.md +207 -0
  750. package/skills/skill-creator/workflows/get-guidance.md +134 -0
  751. package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
  752. package/skills/skill-creator/workflows/verify-skill.md +226 -0
  753. package/skills/skill-security-scan/SKILL.md +145 -0
  754. package/skills/skill-security-scan/references/disclaimer.md +21 -0
  755. package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
  756. package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
  757. package/skills/skill-security-scan/references/override-mechanism.md +171 -0
  758. package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
  759. package/skills/skill-security-scan/references/regex-patterns.md +136 -0
  760. package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
  761. package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
  762. package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
  763. package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
  764. package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
  765. package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
  766. package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
  767. package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
  768. package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
  769. package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
  770. package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
  771. package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
  772. package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
  773. package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
  774. package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
  775. package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
  776. package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
  777. package/skills/skill-security-scan/scripts/lib.sh +197 -0
  778. package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
  779. package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
  780. package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
  781. package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
  782. package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
  783. package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
  784. package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
  785. package/skills/social-distribute/SKILL.md +485 -0
  786. package/skills/spec-templates/SKILL.md +274 -0
  787. package/skills/sync/SKILL.md +49 -0
  788. package/skills/test-browser/SKILL.md +464 -0
  789. package/skills/test-browser/references/feature-map.md +161 -0
  790. package/skills/test-fix-loop/SKILL.md +159 -0
  791. package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
  792. package/skills/triage/SKILL.md +402 -0
  793. package/skills/trigger-cron/SKILL.md +136 -0
  794. package/skills/trigger-cron/scripts/trigger.sh +198 -0
  795. package/skills/user-set-role/SKILL.md +147 -0
  796. package/skills/user-set-role/scripts/set-role.sh +218 -0
  797. package/skills/user-story-writer/SKILL.md +77 -0
  798. package/skills/ux-audit/SKILL.md +251 -0
  799. package/skills/ux-audit/references/finding.schema.json +62 -0
  800. package/skills/ux-audit/references/route-list.yaml +95 -0
  801. package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
  802. package/skills/ux-audit/scripts/bot-signin.ts +135 -0
  803. package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
  804. package/skills/verification-scaffold/SKILL.md +73 -0
  805. package/skills/verification-scaffold/references/gitleaks.toml.template +13 -0
  806. package/skills/verification-scaffold/references/guardrail-audit.md +156 -0
  807. package/skills/verification-scaffold/references/guards/block-stash-hook.sh.template +72 -0
  808. package/skills/verification-scaffold/references/guards/commit-on-main-hook.sh.template +82 -0
  809. package/skills/verification-scaffold/references/guards/orphan-test-check.sh.template +102 -0
  810. package/skills/verification-scaffold/references/guards/precommit-guard.sh.template +115 -0
  811. package/skills/verification-scaffold/references/guards/secret-scan-hook.sh.template +176 -0
  812. package/skills/verification-scaffold/references/guards/verification-gates.yml.template +49 -0
  813. package/skills/verification-scaffold/references/guards/wrapper-boundary.sh.template +47 -0
  814. package/skills/verification-scaffold/references/guards.tsv +21 -0
  815. package/skills/verification-scaffold/references/verification-readme.template +55 -0
  816. package/skills/verification-scaffold/scripts/verification-scaffold.sh +785 -0
  817. package/skills/verification-scaffold/test/bite-proof.test.sh +159 -0
  818. package/skills/verification-scaffold/test/generator.test.sh +319 -0
  819. package/skills/verification-scaffold/test/manifest.test.sh +144 -0
  820. package/skills/work/SKILL.md +1480 -0
  821. package/skills/work/references/end-of-work-resume.md +7 -0
  822. package/skills/work/references/hook-test-main-cwd.md +24 -0
  823. package/skills/work/references/key-principles.md +83 -0
  824. package/skills/work/references/property-testing.md +122 -0
  825. package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
  826. package/skills/work/references/work-agent-teams.md +97 -0
  827. package/skills/work/references/work-lifecycle-parallel.md +147 -0
  828. package/skills/work/references/work-lockfile-bumps.md +97 -0
  829. package/skills/work/references/work-scratch-sandboxes.md +212 -0
  830. package/skills/work/references/work-subagent-fanout.md +61 -0
  831. package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
  832. 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