@soleur/opencode 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (812) 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 +659 -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 +108 -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 +342 -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 +152 -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 +493 -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 +363 -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 +520 -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 +113 -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 +178 -0
  247. package/scripts/sync-opencode-adapter.ts +479 -0
  248. package/scripts/sync-pr-behind.sh +534 -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 +65 -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 +142 -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 +118 -0
  493. package/skills/fix-issue/references/exclude-label-jq-snippet.md +96 -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 +668 -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 +325 -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 +138 -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 +1621 -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-todo-structure.md +165 -0
  674. package/skills/review/references/risk-tier-and-fix-rounds.md +95 -0
  675. package/skills/review/references/semgrep-custom-rules.yaml +174 -0
  676. package/skills/review/references/ultrathink-phases.md +98 -0
  677. package/skills/review/references/wfs.md +6 -0
  678. package/skills/review/scripts/emit-review-trailer.sh +499 -0
  679. package/skills/review/scripts/ensure-semgrep.sh +99 -0
  680. package/skills/review/scripts/fix-round-seats.sh +197 -0
  681. package/skills/review/test/emit-review-trailer.test.sh +387 -0
  682. package/skills/review/test/ensure-semgrep.test.sh +111 -0
  683. package/skills/review/test/fix-round-seats.test.sh +237 -0
  684. package/skills/review/workflows/README.md +147 -0
  685. package/skills/review/workflows/review.workflow.js +667 -0
  686. package/skills/schedule/SKILL.md +796 -0
  687. package/skills/seo-aeo/SKILL.md +139 -0
  688. package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
  689. package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
  690. package/skills/ship/SKILL.md +3022 -0
  691. package/skills/ship/references/adr-ordinal-collision.md +47 -0
  692. package/skills/ship/references/affected-gate-contract.md +115 -0
  693. package/skills/ship/references/ci-run-diagnosis.md +29 -0
  694. package/skills/ship/references/ci-workflow-authoring.md +68 -0
  695. package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
  696. package/skills/ship/references/cto-ruling-armed-push.md +5 -0
  697. package/skills/ship/references/decision-challenges-render.md +71 -0
  698. package/skills/ship/references/detached-battery-verdict.md +13 -0
  699. package/skills/ship/references/feature-tweet-draft.md +42 -0
  700. package/skills/ship/references/followthrough-issue-body-template.md +47 -0
  701. package/skills/ship/references/followthrough-stub-template.sh +92 -0
  702. package/skills/ship/references/merge-queue-dequeue.md +39 -0
  703. package/skills/ship/references/operator-holds.md +149 -0
  704. package/skills/ship/references/pipeline-tally-render.md +43 -0
  705. package/skills/ship/references/pr-overlap.md +153 -0
  706. package/skills/ship/references/queue-mode.md +7 -0
  707. package/skills/ship/references/ready-run-wait.md +36 -0
  708. package/skills/ship/references/red-on-main-quarantine.md +110 -0
  709. package/skills/ship/references/register-update-pr-pattern.md +88 -0
  710. package/skills/ship/references/settle-then-admin-merge.md +130 -0
  711. package/skills/ship/references/supabase-column-probe.md +13 -0
  712. package/skills/ship/scripts/auto-close-scan.sh +76 -0
  713. package/skills/ship/scripts/battery-owed.sh +403 -0
  714. package/skills/ship/scripts/hold-gate-eval.sh +410 -0
  715. package/skills/ship/scripts/net-issue-flow.sh +665 -0
  716. package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
  717. package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
  718. package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
  719. package/skills/skill-creator/SKILL.md +299 -0
  720. package/skills/skill-creator/references/api-security.md +248 -0
  721. package/skills/skill-creator/references/authoring-levers.md +110 -0
  722. package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
  723. package/skills/skill-creator/references/best-practices.md +431 -0
  724. package/skills/skill-creator/references/common-patterns.md +639 -0
  725. package/skills/skill-creator/references/core-principles.md +193 -0
  726. package/skills/skill-creator/references/executable-code.md +188 -0
  727. package/skills/skill-creator/references/iteration-and-testing.md +509 -0
  728. package/skills/skill-creator/references/official-spec.md +193 -0
  729. package/skills/skill-creator/references/recommended-structure.md +180 -0
  730. package/skills/skill-creator/references/skill-structure.md +396 -0
  731. package/skills/skill-creator/references/using-scripts.md +122 -0
  732. package/skills/skill-creator/references/using-templates.md +120 -0
  733. package/skills/skill-creator/references/workflows-and-validation.md +541 -0
  734. package/skills/skill-creator/scripts/init_skill.py +322 -0
  735. package/skills/skill-creator/scripts/package_skill.py +110 -0
  736. package/skills/skill-creator/scripts/quick_validate.py +64 -0
  737. package/skills/skill-creator/templates/router-skill.md +73 -0
  738. package/skills/skill-creator/templates/simple-skill.md +34 -0
  739. package/skills/skill-creator/workflows/add-reference.md +96 -0
  740. package/skills/skill-creator/workflows/add-script.md +104 -0
  741. package/skills/skill-creator/workflows/add-template.md +83 -0
  742. package/skills/skill-creator/workflows/add-workflow.md +128 -0
  743. package/skills/skill-creator/workflows/audit-skill.md +159 -0
  744. package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
  745. package/skills/skill-creator/workflows/create-new-skill.md +207 -0
  746. package/skills/skill-creator/workflows/get-guidance.md +134 -0
  747. package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
  748. package/skills/skill-creator/workflows/verify-skill.md +226 -0
  749. package/skills/skill-security-scan/SKILL.md +145 -0
  750. package/skills/skill-security-scan/references/disclaimer.md +21 -0
  751. package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
  752. package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
  753. package/skills/skill-security-scan/references/override-mechanism.md +171 -0
  754. package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
  755. package/skills/skill-security-scan/references/regex-patterns.md +136 -0
  756. package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
  757. package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
  758. package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
  759. package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
  760. package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
  761. package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
  762. package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
  763. package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
  764. package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
  765. package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
  766. package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
  767. package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
  768. package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
  769. package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
  770. package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
  771. package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
  772. package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
  773. package/skills/skill-security-scan/scripts/lib.sh +197 -0
  774. package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
  775. package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
  776. package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
  777. package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
  778. package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
  779. package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
  780. package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
  781. package/skills/social-distribute/SKILL.md +485 -0
  782. package/skills/spec-templates/SKILL.md +274 -0
  783. package/skills/sync/SKILL.md +49 -0
  784. package/skills/test-browser/SKILL.md +464 -0
  785. package/skills/test-browser/references/feature-map.md +161 -0
  786. package/skills/test-fix-loop/SKILL.md +159 -0
  787. package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
  788. package/skills/triage/SKILL.md +402 -0
  789. package/skills/trigger-cron/SKILL.md +136 -0
  790. package/skills/trigger-cron/scripts/trigger.sh +198 -0
  791. package/skills/user-set-role/SKILL.md +147 -0
  792. package/skills/user-set-role/scripts/set-role.sh +218 -0
  793. package/skills/user-story-writer/SKILL.md +77 -0
  794. package/skills/ux-audit/SKILL.md +251 -0
  795. package/skills/ux-audit/references/finding.schema.json +62 -0
  796. package/skills/ux-audit/references/route-list.yaml +95 -0
  797. package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
  798. package/skills/ux-audit/scripts/bot-signin.ts +135 -0
  799. package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
  800. package/skills/work/SKILL.md +1479 -0
  801. package/skills/work/references/end-of-work-resume.md +7 -0
  802. package/skills/work/references/hook-test-main-cwd.md +24 -0
  803. package/skills/work/references/key-principles.md +83 -0
  804. package/skills/work/references/property-testing.md +122 -0
  805. package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
  806. package/skills/work/references/work-agent-teams.md +97 -0
  807. package/skills/work/references/work-lifecycle-parallel.md +147 -0
  808. package/skills/work/references/work-lockfile-bumps.md +97 -0
  809. package/skills/work/references/work-scratch-sandboxes.md +212 -0
  810. package/skills/work/references/work-subagent-fanout.md +61 -0
  811. package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
  812. package/skills/xcode-test/SKILL.md +360 -0
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # alpha-metrics.sh -- print the aggregate a tester pastes back at checkpoint.
4
+ #
5
+ # Usage: run inside the project repo: bash plugins/soleur/scripts/alpha-metrics.sh
6
+ #
7
+ # Reads .soleur/decisions.jsonl (and the rotated .1) at the git root and prints
8
+ # aggregate counts ONLY: total lines, per-skill / per-agent_domain / per-harness
9
+ # breakdowns, first/last timestamps. Metadata is already allowlisted at write
10
+ # time, but this script still prints counts and fields only — never raw lines.
11
+ #
12
+ # Missing or empty output is a SIGNAL, not a zero:
13
+ # SOLEUR_EMIT_ABSENT -- no log exists (stale install / emit never ran)
14
+ # SOLEUR_EMIT_EMPTY -- log exists with zero records (kill-switch set,
15
+ # unwritable dir, or a brand-new install)
16
+ # Neither means "the tester did nothing". Never report absence as zero usage.
17
+ #
18
+ # Portability: awk/grep/sed/wc/sort/head only — stock macOS bash 3.2-safe.
19
+
20
+ set -uo pipefail
21
+
22
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ # shellcheck source=plugins/soleur/scripts/resolve-git-root.sh
24
+ . "$DIR/resolve-git-root.sh" 2>/dev/null || {
25
+ echo "SOLEUR_EMIT_ABSENT — not inside a git repository"
26
+ exit 0
27
+ }
28
+
29
+ LOG_DIR="$GIT_ROOT/.soleur"
30
+ LOG="$LOG_DIR/decisions.jsonl"
31
+ ROT="$LOG.1"
32
+
33
+ if [ ! -f "$LOG" ] && [ ! -f "$ROT" ]; then
34
+ echo "SOLEUR_EMIT_ABSENT — no decision log at .soleur/decisions.jsonl"
35
+ echo "(a stale plugin install or emit has never fired; this is NOT proof of zero usage)"
36
+ exit 0
37
+ fi
38
+
39
+ if [ ! -s "$LOG" ] && [ ! -s "$ROT" ]; then
40
+ echo "SOLEUR_EMIT_EMPTY — the log exists but holds no records"
41
+ echo "(kill-switch SOLEUR_DISABLE_DECISION_LOG, an unwritable .soleur, or a brand-new install)"
42
+ exit 0
43
+ fi
44
+
45
+ # Merge current + rotated; each line is one allowlisted JSON object.
46
+ INPUT="$(cat "$LOG" "$ROT" 2>/dev/null)"
47
+
48
+ total="$(printf '%s\n' "$INPUT" | grep -c '^{"v":' )"
49
+ lines="$(printf '%s\n' "$INPUT" | grep -c .)"
50
+ malformed=$((lines - total))
51
+ first="$(printf '%s\n' "$INPUT" | sed -n 's/.*"ts":"\([^"]*\)".*/\1/p' | sort | head -1)"
52
+ last="$(printf '%s\n' "$INPUT" | sed -n 's/.*"ts":"\([^"]*\)".*/\1/p' | sort | tail -1)"
53
+
54
+ echo "=== .soleur/decisions.jsonl aggregate ==="
55
+ echo "records: $total"
56
+ [ "$malformed" -gt 0 ] && echo "malformed: $malformed line(s) skipped (corrupt log — not counted)"
57
+ echo "first: ${first:-unknown}"
58
+ echo "last: ${last:-unknown}"
59
+ echo
60
+
61
+ count_field() { # $1 = json field name
62
+ printf '%s\n' "$INPUT" \
63
+ | sed -n "s/.*\"$1\":\"\([^\"]*\)\".*/\1/p" \
64
+ | grep -v '^$' \
65
+ | sort | uniq -c | sort -rn \
66
+ | awk '{printf " %-6s %s\n", $1, $2}'
67
+ }
68
+
69
+ echo "by event:"; count_field event
70
+ echo "by label:"; count_field label
71
+ echo "by skill:"; count_field skill
72
+ echo "by agent_domain:"; count_field agent_domain
73
+ echo "by harness:"; count_field harness
74
+
75
+ echo
76
+ echo "Knowledge-base growth (run in this repo):"
77
+ echo " git log --since=<onboard-date> --name-only -- knowledge-base/ | grep -c '^knowledge-base/'"
78
+ exit 0
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Tests for alpha-metrics.sh — the checkpoint aggregate printer.
4
+ #
5
+ # Load-bearing contract: ABSENT/EMPTY markers must render as signals, never as
6
+ # a zero count. A tester who did nothing and a tester whose emit never ran are
7
+ # different worlds; the print must not conflate them.
8
+
9
+ set -uo pipefail
10
+ export TMPDIR="${TMPDIR:-/var/tmp}"
11
+
12
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
+ SUT="$DIR/alpha-metrics.sh"
14
+ EMIT="$DIR/emit-decision.sh"
15
+
16
+ # trap BEFORE sourcing test-helpers.sh so the helpers' composed EXIT trap
17
+ # (<prior>; _soleur_sb_cleanup) stacks on ours instead of being clobbered by it.
18
+ TMP="$(mktemp -d -t alpham.XXXXXXXX)" || { echo "mktemp failed" >&2; exit 2; }
19
+ trap 'rm -rf "$TMP"' EXIT
20
+
21
+ # shellcheck source=plugins/soleur/test/test-helpers.sh
22
+ source "$DIR/../test/test-helpers.sh" || { echo "FATAL: could not source test-helpers.sh" >&2; exit 2; }
23
+ set +e -uo pipefail
24
+
25
+ passes=0
26
+ fails=0
27
+ CASES=0
28
+
29
+ pass() { passes=$((passes + 1)); printf ' ok %s\n' "$1"; }
30
+ fail() { fails=$((fails + 1)); printf ' FAIL %s\n' "$1"; [[ -n "${2:-}" ]] && printf ' %s\n' "$2"; return 0; }
31
+ assert() {
32
+ CASES=$((CASES + 1))
33
+ if eval "$2"; then pass "$1"; else fail "$1" "${3:-$2}"; fi
34
+ }
35
+
36
+ printf '\n=== alpha-metrics.sh ===\n\n'
37
+ [[ -f "$SUT" ]] || { printf '\n[FATAL] SUT missing at %s\n' "$SUT" >&2; exit 1; }
38
+
39
+ new_repo() { # $1 = name
40
+ local d="$TMP/$1"; mkdir -p "$d"
41
+ git -C "$d" init -q -b main
42
+ git -C "$d" config user.email soleur-test@example.invalid
43
+ git -C "$d" config user.name "Soleur Test"
44
+ git -C "$d" config commit.gpgsign false
45
+ git -C "$d" commit -q --allow-empty -m "base"
46
+ printf '%s' "$d"
47
+ }
48
+
49
+ # --- ABSENT: no log at all --------------------------------------------------
50
+
51
+ RA="$TMP/no-log"; new_repo no-log >/dev/null
52
+ out="$(cd "$RA" && bash "$SUT")"
53
+ assert "missing log -> SOLEUR_EMIT_ABSENT" "[[ '$out' == *SOLEUR_EMIT_ABSENT* ]]"
54
+ assert "absent never prints a zero count" "! printf '%s' '$out' | grep -c >/dev/null 'records: *0'"
55
+
56
+ # --- EMPTY: log exists, zero records -----------------------------------------
57
+
58
+ RB="$TMP/empty-log"; new_repo empty-log >/dev/null
59
+ mkdir -p "$RB/.soleur"; touch "$RB/.soleur/decisions.jsonl"
60
+ out="$(cd "$RB" && bash "$SUT")"
61
+ assert "empty log -> SOLEUR_EMIT_EMPTY" "[[ '$out' == *SOLEUR_EMIT_EMPTY* ]]"
62
+ assert "empty never prints a zero count" "! printf '%s' '$out' | grep -c >/dev/null 'records: *0'"
63
+
64
+ # --- POPULATED: real emits aggregate -----------------------------------------
65
+
66
+ RC="$TMP/pop"; new_repo pop >/dev/null
67
+ ( cd "$RC"
68
+ bash "$EMIT" --event route_decision --label work
69
+ bash "$EMIT" --event route_decision --label brainstorm
70
+ bash "$EMIT" --event route_decision --label work
71
+ bash "$EMIT" --event tool_invocation --label flag-list --skill flag-list --agent_domain ops )
72
+ out="$(cd "$RC" && bash "$SUT")"
73
+ assert "counts 4 records" "printf '%s' '$out' | grep -c >/dev/null 'records: *4'"
74
+ assert "per-event count present" "printf '%s' '$out' | grep -A3 'by event:' | grep -c >/dev/null 'route_decision'"
75
+ assert "per-label count shows work=2" "printf '%s' '$out' | grep -A5 'by label:' | grep -cE >/dev/null '^ *2 +work'"
76
+ assert "per-domain count shows ops=1" "printf '%s' '$out' | grep -A4 'by agent_domain:' | grep -c >/dev/null 'ops'"
77
+ assert "per-harness count is non-empty" "printf '%s' '$out' | grep -A3 'by harness:' | grep -cE >/dev/null '^ *[0-9]+ +[a-zA-Z]'"
78
+ assert "first/last timestamps printed" "printf '%s' '$out' | grep -c >/dev/null 'first:' && printf '%s' '$out' | grep -c >/dev/null 'last:'"
79
+ assert "KB-growth instruction printed" "printf '%s' '$out' | grep -c >/dev/null 'git log --since'"
80
+
81
+ # --- ROTATED: merged read ----------------------------------------------------
82
+
83
+ RD="$TMP/rot"; new_repo rot >/dev/null
84
+ ( cd "$RD" && bash "$EMIT" --event route_decision --label one )
85
+ printf '{"v":1,"ts":"2026-01-01T00:00:00Z","event":"route_decision","label":"old","skill":"","agent_domain":"","harness":"claude","session_id":"s","plugin_sha":"x","repo_hash":"h"}\n' > "$RD/.soleur/decisions.jsonl.1"
86
+ out="$(cd "$RD" && bash "$SUT")"
87
+ assert "rotated lines merge into the count" "printf '%s' '$out' | grep -c >/dev/null 'records: *2'"
88
+
89
+ # --- ORDERING: first/last carry VALUES, not just labels ----------------------
90
+
91
+ RE="$TMP/order"; new_repo order >/dev/null
92
+ mkdir -p "$RE/.soleur"
93
+ printf '%s\n' '{"v":1,"ts":"2026-03-05T00:00:00Z","event":"route_decision","label":"b","skill":"","agent_domain":"","harness":"x","session_id":"s","plugin_sha":"p","repo_hash":"h"}' \
94
+ '{"v":1,"ts":"2026-03-01T00:00:00Z","event":"route_decision","label":"a","skill":"","agent_domain":"","harness":"x","session_id":"s","plugin_sha":"p","repo_hash":"h"}' \
95
+ > "$RE/.soleur/decisions.jsonl"
96
+ out="$(cd "$RE" && bash "$SUT")"
97
+ assert "first: carries the EARLIEST ts (not just the label)" \
98
+ "printf '%s' '$out' | grep -c >/dev/null 'first: 2026-03-01'"
99
+ assert "last: carries the LATEST ts" \
100
+ "printf '%s' '$out' | grep -c >/dev/null 'last: 2026-03-05'"
101
+
102
+ # --- CORRUPTION: a malformed line is surfaced, not silently counted ----------
103
+
104
+ RF="$TMP/bad"; new_repo bad >/dev/null
105
+ mkdir -p "$RF/.soleur"
106
+ printf '%s\n' '{"v":1,"ts":"2026-03-01T00:00:00Z","event":"route_decision","label":"ok","skill":"","agent_domain":"","harness":"x","session_id":"s","plugin_sha":"p","repo_hash":"h"}' \
107
+ 'garbage-not-json' \
108
+ > "$RF/.soleur/decisions.jsonl"
109
+ out="$(cd "$RF" && bash "$SUT")"
110
+ assert "malformed lines are reported, not silently dropped" \
111
+ "printf '%s' '$out' | grep -c >/dev/null 'malformed: 1'"
112
+
113
+ printf '\n=== alpha-metrics: %d passed, %d failed (of %d) ===\n' "$passes" "$fails" "$CASES"
114
+ # Anti-vacuity floor (#7408 class): a suite that ran nothing must not exit green.
115
+ [[ "$fails" -eq 0 && "$CASES" -ge 15 ]]
@@ -0,0 +1,16 @@
1
+ # ancestor-signal baseline: one row per gated finding, <path> TAB <class> TAB <normalised line>.
2
+ # Classes: W ancestor walk that signals (must read bounded=yes), P signal to the parent, G all-process signal.
3
+ # Maintenance: an in-place replacement of an existing row (same path and class, e.g. after an unrelated edit of
4
+ # that line) is allowed; a net addition needs a reviewer's read; otherwise the file may only shrink. A stale row
5
+ # (no live line) and an unbounded W are red. bounded=yes is LEXICAL (a non-comment SOLEUR_TEST_SUITE_PID
6
+ # comparison with exit, break or return near the walk), not proof of containment.
7
+ # Regenerate: python3 plugins/soleur/scripts/scan-ancestor-signal-helpers.py --write-baseline <this file>
8
+ # (overwrites the whole file: review the diff row by row).
9
+ apps/web-platform/infra/arm-heartbeats.test.sh P if [[ "$seen" -ge "$FAKE_CUT_AFTER" ]]; then kill -9 "$PPID" 2>/dev/null; exit 0; fi
10
+ apps/web-platform/infra/git-data-luks-reopen.test.sh P [ -f "$FX/luksopen_kill" ] && kill -TERM "$PPID"
11
+ apps/web-platform/infra/run-registered-suites.test.sh P kill -9 "$_shim" 2>/dev/null
12
+ apps/web-platform/infra/workspaces-boot-unlock.test.sh P [ -f "$FX/luksopen_kill" ] && kill -TERM "$PPID"
13
+ apps/web-platform/infra/workspaces-luks-provision.test.sh P [ -f "$st/crash_after_luksFormat" ] && kill -9 "$PPID"
14
+ apps/web-platform/infra/workspaces-luks-provision.test.sh P [ -f "$st/crash_after_mkfs" ] && kill -9 "$PPID"
15
+ plugins/soleur/scripts/resolve-regenerable-conflicts.test.sh W p=$(awk '{print $4}' "/proc/$p/stat" 2>/dev/null)
16
+ plugins/soleur/test/roadmap-reconcile.test.sh W top=$p; p=$(awk '{print $4}' "/proc/$p/stat")
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env bash
2
+ # Shared WORM audit-append helper for the flag-tooling skills (#4581 PR-1).
3
+ #
4
+ # Appends a row to public.flag_flip_audit via the SECURITY DEFINER PostgREST RPC
5
+ # `audit_flag_flip` (migration 071), replacing the prior `psql` binary dependency
6
+ # so the sanctioned path runs on any machine (no psql/sudo).
7
+ #
8
+ # Sourced by:
9
+ # plugins/soleur/skills/flag-create/scripts/create.sh
10
+ # plugins/soleur/skills/flag-delete/scripts/delete.sh
11
+ # plugins/soleur/skills/flag-set-role/scripts/flip.sh
12
+ # plugins/soleur/skills/user-set-role/scripts/set-role.sh
13
+ #
14
+ # Contract:
15
+ # audit_flag_flip_rpc <url> <srk> <flag> <env> <target> <action> <before> <after> <actor>
16
+ #
17
+ # <url> SUPABASE_URL of the audit DB (callers resolve from Doppler -c dev,
18
+ # matching the historical DATABASE_URL_POOLER -c dev audit target).
19
+ # <srk> SUPABASE_SERVICE_ROLE_KEY for <url> (the RPC is GRANTed to service_role only).
20
+ # <before>/<after> LITERAL JSON tokens: `true` | `false` | `null`. Passed via
21
+ # `jq --argjson` so they reach the bool columns as JSON bool/null,
22
+ # not strings (a `--arg` string fails PostgREST bool coercion).
23
+ #
24
+ # Approval method (#8486, ADR-249): the body carries p_approval_method:"tty-ack"
25
+ # (migration 140) ONLY when the operator-script library's class-2 ack has set the
26
+ # plain shell variable SOLEUR_OP_ACKED=tty-ack in this process. Without it the
27
+ # helper refuses with rc 4 before any request, so an audit append placed before
28
+ # the ack fails closed and the WORM value means "the ack returned here". The
29
+ # value is self-reported by the script, not proof that a person typed.
30
+ #
31
+ # Behavior: append-before-flip — the caller MUST call this BEFORE any Flagsmith /
32
+ # Supabase mutation, and abort the flip on a non-zero return. Returns:
33
+ # 0 audit row written (echoes the row uuid on stdout)
34
+ # 4 audit append failed (non-2xx, empty body, or missing/null id) — caller exits 4
35
+ #
36
+ # Requires: curl, jq.
37
+ audit_flag_flip_rpc() {
38
+ local url="$1" srk="$2" flag="$3" env="$4" target="$5" action="$6" before="$7" after="$8" actor="$9"
39
+ local body resp code id
40
+
41
+ # Observability (review #8650): the WORM audit trail failing is the one failure
42
+ # this script's own contract exists to make impossible to miss. stderr alone is
43
+ # sufficient for an ack-refusal (the operator is at the keyboard that just typed
44
+ # `yes`), but a durable, names-not-values ledger row survives past a scrolled
45
+ # terminal. `soleur_op_ledger_note` is defined by operator-script.sh, which every
46
+ # caller sources before this function is ever invoked (append-before-flip runs
47
+ # after the ack) — guard with `declare -F` so this stays safe if that assumption
48
+ # ever stops holding.
49
+ # Always returns 0 — this is bookkeeping around a failure already being
50
+ # reported, and running under the caller's `set -e` a nonzero return here
51
+ # would abort the function before its own `return 4` executes.
52
+ _audit_failed_marker() {
53
+ printf 'SOLEUR_BOOTSTRAP_AUDIT_APPEND_FAILED reason=%s\n' "$1" >&2
54
+ if declare -F soleur_op_ledger_note >/dev/null 2>&1; then
55
+ soleur_op_ledger_note audit_append_failed "$flag" "$1" || true
56
+ fi
57
+ return 0
58
+ }
59
+
60
+ if [[ "${SOLEUR_OP_ACKED:-}" != "tty-ack" ]]; then
61
+ echo "FATAL: audit append before the ack — the class-2 yes prompt has not returned in this process (#8486)" >&2
62
+ _audit_failed_marker no-ack
63
+ return 4
64
+ fi
65
+ command -v jq >/dev/null || { echo "FATAL: jq not found (audit append)" >&2; _audit_failed_marker no-jq; return 4; }
66
+ command -v curl >/dev/null || { echo "FATAL: curl not found (audit append)" >&2; _audit_failed_marker no-curl; return 4; }
67
+
68
+ # --argjson for the bool/null args; --arg for the text args.
69
+ body=$(jq -nc \
70
+ --arg f "$flag" --arg e "$env" --arg t "$target" \
71
+ --arg a "$action" --arg ac "$actor" --arg am "$SOLEUR_OP_ACKED" \
72
+ --argjson b "$before" --argjson af "$after" \
73
+ '{p_flag_name:$f, p_env:$e, p_target:$t, p_action:$a, p_before_bool:$b, p_after_bool:$af, p_actor:$ac, p_approval_method:$am}') \
74
+ || { echo "FATAL: failed to build audit RPC body (bad before/after token: '$before'/'$after')" >&2; _audit_failed_marker bad-body; return 4; }
75
+
76
+ # Token-shape guard (never echoes the value): the key is written into curl's stdin
77
+ # config below, so a quote or newline in it would inject a config directive. An
78
+ # unusable key makes zero curl calls and the same failure outcome (rc 4) as any other
79
+ # failed append, never success.
80
+ _audit_bearer_ok() { local LC_ALL=C; case "${1:-}" in ''|*[!A-Za-z0-9._~+/=-]*) return 1 ;; esac; }
81
+ _audit_bearer_ok "$srk" \
82
+ || { echo "FATAL: audit append key has an unexpected shape (not sent)" >&2; _audit_failed_marker bad-key-shape; return 4; }
83
+
84
+ # The service-role key rides curl's stdin config channel (both the apikey and the
85
+ # Authorization header), never its argument list.
86
+ resp=$(curl --disable --noproxy '*' -sS -w '\n%{http_code}' -X POST \
87
+ -H "Content-Type: application/json" -H "Accept: application/json" \
88
+ --config - \
89
+ "${url}/rest/v1/rpc/audit_flag_flip" -d "$body" \
90
+ < <(printf 'header = "apikey: %s"\nheader = "Authorization: Bearer %s"\n' "$srk" "$srk")) \
91
+ || { echo "FATAL: audit RPC request failed (transport error)" >&2; _audit_failed_marker curl-error; return 4; }
92
+
93
+ code=$(printf '%s' "$resp" | tail -n1)
94
+ body=$(printf '%s' "$resp" | sed '$d')
95
+ [[ "$code" =~ ^2[0-9][0-9]$ ]] \
96
+ || { echo "FATAL: audit RPC non-2xx (HTTP $code): $body" >&2; _audit_failed_marker "http-$code"; return 4; }
97
+
98
+ # RETURNS uuid -> PostgREST emits a bare JSON scalar; array branch is dead-but-safe.
99
+ # `|| id=""` makes the no-id path deterministic under the caller's `set -e` (a jq
100
+ # parse failure on garbage/empty body would otherwise abort the subshell before the
101
+ # guard); the uuid-shape match then rejects empty/null/non-uuid (incl. a 2xx `{}`).
102
+ id=$(printf '%s' "$body" | jq -r 'if type=="array" then .[0] else . end' 2>/dev/null) || id=""
103
+ [[ "$id" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] \
104
+ || { echo "FATAL: audit RPC returned no valid uuid: $body" >&2; _audit_failed_marker no-valid-uuid; return 4; }
105
+
106
+ printf '%s' "$id"
107
+ }
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env bash
2
+ # check-red-on-main.sh "<check-name>" --run-id <failing-run-id> [--report] [--repo owner/repo]
3
+ # check-red-on-main.sh --self-test
4
+ # check-red-on-main.sh --help
5
+ #
6
+ # WHY THIS EXISTS (#9402). A PR whose check is red because MAIN is red pays rerun cycles and
7
+ # autonomous-fix attempts for a failure it did not cause -- PR #9339 paid three reruns of
8
+ # `deploy-script-tests (1/4)` while that leg was red on main. "Confirmed pre-existing" was an
9
+ # agent judgment call with no mechanical probe; this script is the probe. It answers one
10
+ # question: did the newest completed main-branch run of the SAME workflow that exercised a job
11
+ # of the EXACT same name conclude it non-green?
12
+ #
13
+ # HOW IT DECIDES.
14
+ # * The failing check's workflow is resolved through the run it failed in:
15
+ # `gh api repos/{o}/{r}/actions/runs/<run-id>` -> .workflow_id. `gh pr checks`' `link` field
16
+ # already carries `actions/runs/<run-id>`.
17
+ # * Up to 5 completed main-branch runs of that workflow are listed, newest first
18
+ # (`actions/workflows/<id>/runs?branch=main&status=completed&per_page=5`).
19
+ # * In each run the job named EXACTLY <check-name> is looked up. Matrix suffixes like `(1/4)`
20
+ # are part of the name -- the parent `deploy-script-tests` never answers for the leg, and a
21
+ # prefix match would read a green parent as a green leg.
22
+ # * skipped/absent jobs are NOT evidence: a path-filtered main push that never ran the job
23
+ # says nothing, so the scan continues to older runs in the window.
24
+ # * The FIRST run where the job reached a real conclusion decides:
25
+ # red-on-main -- conclusion in {failure, timed_out, cancelled, startup_failure}
26
+ # green-on-main -- conclusion in {success, neutral}
27
+ # no-evidence -- no run in the window exercised the job -> NOT quarantined
28
+ # `cancelled` is red by the same `!= 'success'` convention notify-main-failure uses;
29
+ # `startup_failure` is red because the runner never got to measure the job. `skipped`,
30
+ # `stale`, and `action_required` are not evidence -- the job never produced a verdict
31
+ # on code, so the scan continues to older runs in the window.
32
+ #
33
+ # EXIT CODES (the contract every caller branches on).
34
+ # 0 green-on-main the check is healthy on main -- this PR's red is its own
35
+ # 1 red-on-main same-named job is red on the newest exercising main run -> quarantine
36
+ # 2 no-evidence no main run in the window exercised the job -> NOT quarantined
37
+ # 3 error usage error, gh/jq missing, API failure, unparseable body.
38
+ # ERRORS NEVER QUARANTINE -- an unproven claim is worse than a rerun.
39
+ #
40
+ # Every invocation prints exactly one stdout marker as its LAST stdout line:
41
+ # SOLEUR_RED_ON_MAIN verdict=<v> check="<name>" main_run=<id|none> main_conclusion=<c|none>
42
+ # with ` reason=<api|parse|missing-tool|usage|mktemp|interrupted>` appended on the error
43
+ # path. All diagnostics go
44
+ # to stderr so the marker is the only stdout line.
45
+ #
46
+ # --report (the only write path; dedupe is sentinel-keyed, mirroring main-health-monitor):
47
+ # * red-on-main: list open `ci/main-broken` issues, find those carrying
48
+ # `<!-- soleur:red-on-main check="<name>" -->` (oldest first), comment on the oldest; if
49
+ # none, `gh label create ci/main-broken --force 2>/dev/null || true` then file with
50
+ # --milestone "Post-MVP / Later" --label ci/main-broken --label meta/machinery --label
51
+ # type/chore. A LIST FAILURE warns and files NOTHING -- never a duplicate on a transient
52
+ # error (#1357 lesson: the rate-limit response is this query's own failure condition).
53
+ # * green-on-main: comment-and-close EVERY open issue carrying OUR sentinel for that exact
54
+ # check name -- never a human-filed tracker, never another check's sentinel (#7374's
55
+ # out-of-scope-green lesson is what the sentinel encodes).
56
+ # * no-evidence/error: no issue operations at all.
57
+ #
58
+ # `gh api` GET calls embed the query in the URL -- never `-f`/`--raw-field`, which flips the
59
+ # request to POST and 404s the actions runs endpoints (measured 2026-09-29, PR #9233). And
60
+ # `gh api` has no `--arg` (cli/cli#10263): two-stage `gh api URL | jq --arg` is the only
61
+ # sanctioned shape. `gh api` also has no `-R/--repo` flag, so --repo is embedded in the path.
62
+ set -uo pipefail
63
+
64
+ readonly MARKER="SOLEUR_RED_ON_MAIN"
65
+
66
+ usage() {
67
+ cat <<'EOF'
68
+ usage: check-red-on-main.sh "<check-name>" --run-id <failing-run-id> [--report] [--repo owner/repo]
69
+ check-red-on-main.sh --self-test
70
+ check-red-on-main.sh --help
71
+
72
+ Answers whether the check that failed in run <failing-run-id> is ALSO failing on main: scans up
73
+ to 5 completed main-branch runs of the same workflow, newest first, for a job named EXACTLY
74
+ <check-name> (matrix suffixes included). Skipped/absent jobs are not evidence.
75
+
76
+ exit 0 green-on-main | 1 red-on-main (quarantine) | 2 no-evidence (not quarantined) | 3 error
77
+
78
+ Last stdout line, on every path except --help and --self-test:
79
+ SOLEUR_RED_ON_MAIN verdict=<v> check="<name>" main_run=<id|none> main_conclusion=<c|none> [reason=<r>]
80
+
81
+ --report files/dedupes a `ci/main-broken` tracker keyed on the sentinel
82
+ `<!-- soleur:red-on-main check="<name>" -->` on red, and comments+closes sentinel-owned issues
83
+ on green. Errors and no-evidence never file and never close.
84
+ EOF
85
+ }
86
+
87
+ CHECK_OUT="-"; MAIN_RUN="none"; MAIN_CONCL="none"; REASON="none"
88
+
89
+ marker() { # <verdict> ; always the LAST stdout line
90
+ if [[ "$1" == error ]]; then
91
+ printf '%s verdict=error check="%s" main_run=%s main_conclusion=%s reason=%s\n' \
92
+ "$MARKER" "$CHECK_OUT" "$MAIN_RUN" "$MAIN_CONCL" "$REASON"
93
+ else
94
+ printf '%s verdict=%s check="%s" main_run=%s main_conclusion=%s\n' \
95
+ "$MARKER" "$1" "$CHECK_OUT" "$MAIN_RUN" "$MAIN_CONCL"
96
+ fi
97
+ }
98
+
99
+ die3() { # <message> <reason-token>
100
+ printf 'check-red-on-main: ERROR: %s\n' "$1" >&2
101
+ REASON="$2"; marker error; exit 3
102
+ }
103
+
104
+ usage_error() {
105
+ printf 'check-red-on-main: %s\n' "$1" >&2
106
+ usage >&2
107
+ REASON=usage; marker error; exit 3
108
+ }
109
+
110
+ # ── the pure classifier ─────────────────────────────────────────────────────────────────────
111
+ # job_verdict <check-name> -- reads ONE OR MORE concatenated jobs-page objects on stdin (the
112
+ # `gh api --paginate` output shape) and prints "<red|green|none> <conclusion-or->". `none`
113
+ # covers absent, skipped, stale, action_required, and still-running jobs alike: only a real
114
+ # conclusion is evidence.
115
+ job_verdict() {
116
+ local name="$1" pair
117
+ pair=$(jq -sr --arg n "$name" '
118
+ [ .[] | .jobs[]? | select(.name == $n) ] as $m
119
+ | if ($m | length) == 0 then "ABSENT -"
120
+ else (((($m | map(select(.status == "completed")) | .[0]) // $m[0]).status // "-")
121
+ + " " + (((($m | map(select(.status == "completed")) | .[0]) // $m[0]).conclusion // "-"))) end') \
122
+ || return 3
123
+ case "$pair" in
124
+ "completed failure"|"completed timed_out"|"completed cancelled"|"completed startup_failure") echo "red ${pair#* }" ;;
125
+ "completed success"|"completed neutral") echo "green ${pair#* }" ;;
126
+ *) echo "none ${pair#* }" ;;
127
+ esac
128
+ }
129
+
130
+ self_test() {
131
+ command -v jq >/dev/null 2>&1 || { echo "check-red-on-main: jq required for --self-test" >&2; exit 3; }
132
+ local name='deploy-script-tests (1/4)' fails=0
133
+ st() { # <want-verdict> <json-docs...>
134
+ local want="$1"; shift
135
+ local doc got=""
136
+ for doc in "$@"; do got+="$doc"$'\n'; done
137
+ got=$(printf '%s' "$got" | job_verdict "$name") || { echo " self-test: job_verdict errored" >&2; fails=$((fails + 1)); return; }
138
+ [[ "${got%% *}" == "$want" ]] || { echo " self-test: want $want, got '$got'" >&2; fails=$((fails + 1)); }
139
+ }
140
+ st red '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"failure"}]}'
141
+ st red '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"cancelled"}]}'
142
+ st red '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"timed_out"}]}'
143
+ st red '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"startup_failure"}]}'
144
+ st green '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"success"}]}'
145
+ st green '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"neutral"}]}'
146
+ st none '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"skipped"}]}'
147
+ st none '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"stale"}]}'
148
+ st none '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"action_required"}]}'
149
+ st none '{"jobs":[{"name":"deploy-script-tests (1/4)","status":"in_progress","conclusion":null}]}'
150
+ st none '{"jobs":[{"name":"deploy-script-tests","status":"completed","conclusion":"failure"}]}'
151
+ st none '{"jobs":[{"name":"lint","status":"completed","conclusion":"failure"}]}'
152
+ # two concatenated page objects (the --paginate output shape) must still find the job
153
+ st red '{"total_count":41,"jobs":[{"name":"lint","status":"completed","conclusion":"success"}]}' \
154
+ '{"total_count":41,"jobs":[{"name":"deploy-script-tests (1/4)","status":"completed","conclusion":"failure"}]}'
155
+ if (( fails > 0 )); then
156
+ printf 'SOLEUR_RED_ON_MAIN_SELFTEST failed (%s case(s))\n' "$fails" >&2; exit 3
157
+ fi
158
+ echo "SOLEUR_RED_ON_MAIN_SELFTEST ok"
159
+ exit 0
160
+ }
161
+
162
+ # ── args ──────────────────────────────────────────────────────────────────────────────────────
163
+ CHECK=""; RUN_ID=""; REPORT=0; REPO=""; SELFTEST=0
164
+ while [[ $# -gt 0 ]]; do
165
+ case "$1" in
166
+ --self-test) SELFTEST=1; shift ;;
167
+ --help|-h) usage; exit 0 ;;
168
+ --run-id)
169
+ [[ "${2-}" =~ ^[0-9]+$ ]] || usage_error "--run-id needs a numeric workflow-run id"
170
+ RUN_ID="$2"; shift 2 ;;
171
+ --report) REPORT=1; shift ;;
172
+ --repo)
173
+ [[ "${2-}" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || usage_error "--repo needs owner/repo"
174
+ REPO="$2"; shift 2 ;;
175
+ -*) usage_error "unknown flag $1" ;;
176
+ *) [[ -z "$CHECK" ]] || usage_error "unexpected extra argument $1"; CHECK="$1"; shift ;;
177
+ esac
178
+ done
179
+ (( SELFTEST == 1 )) && self_test
180
+ [[ -n "$CHECK" ]] || usage_error "<check-name> is required"
181
+ # Check names are PR-author-controlled text reaching the operator's terminal, the stdout
182
+ # marker, and (under --report) issue titles/bodies: control characters would let a crafted
183
+ # name forge terminal escapes, split the monitor's TSV rows, or break the sentinel.
184
+ [[ "$CHECK" != *'"'* && "$CHECK" != *'-->'* && "$CHECK" != *[[:cntrl:]]* && "$CHECK" != *$'\x7f'* ]] \
185
+ || usage_error "check name cannot carry a double-quote, a control character, or '-->' (sentinel/marker safety)"
186
+ CHECK_OUT="$CHECK"
187
+ [[ -n "$RUN_ID" ]] || usage_error "--run-id <failing-run-id> is required"
188
+
189
+ for bin in gh jq; do
190
+ command -v "$bin" >/dev/null 2>&1 || { echo "check-red-on-main: ERROR: $bin not found on PATH" >&2; REASON="missing-tool"; marker error; exit 3; }
191
+ done
192
+
193
+ WORK="$(mktemp -d)" || { echo "check-red-on-main: ERROR: mktemp failed" >&2; REASON=mktemp; marker error; exit 3; }
194
+ trap 'rm -rf "$WORK"' EXIT
195
+ trap 'REASON=interrupted; marker error; exit 130' INT TERM HUP
196
+
197
+ # gh api has no -R/--repo flag: --repo is embedded in the endpoint path instead.
198
+ if [[ -n "$REPO" ]]; then RP="repos/$REPO"; REPO_ARG=(--repo "$REPO"); else RP="repos/{owner}/{repo}"; REPO_ARG=(); fi
199
+
200
+ # ── resolve the workflow through the failing run ─────────────────────────────────────────────
201
+ gh api "$RP/actions/runs/$RUN_ID" > "$WORK/run.json" 2>"$WORK/gh-err" \
202
+ || die3 "gh api actions/runs/$RUN_ID failed: $(head -c 200 "$WORK/gh-err" | tr '\n' ' ')" api
203
+ jq -e 'type == "object" and (.workflow_id | type) == "number"' "$WORK/run.json" >/dev/null 2>&1 \
204
+ || die3 "unparseable actions/runs/$RUN_ID response (no numeric workflow_id)" parse
205
+ WFID=$(jq -r '.workflow_id' "$WORK/run.json")
206
+
207
+ # ── windowed scan of completed main runs, newest first ───────────────────────────────────────
208
+ gh api "$RP/actions/workflows/$WFID/runs?branch=main&status=completed&per_page=5" > "$WORK/wfruns.json" 2>"$WORK/gh-err" \
209
+ || die3 "gh api workflows/$WFID/runs failed: $(head -c 200 "$WORK/gh-err" | tr '\n' ' ')" api
210
+ jq -e 'type == "object" and (.workflow_runs | type) == "array"' "$WORK/wfruns.json" >/dev/null 2>&1 \
211
+ || die3 "unparseable workflow-runs response" parse
212
+ IDS_RAW=$(jq -r '[.workflow_runs[:5][] | .id | select(type == "number")] | .[]' "$WORK/wfruns.json") \
213
+ || die3 "unparseable workflow-runs response" parse
214
+
215
+ OUTCOME=""
216
+ while IFS= read -r rid; do
217
+ [[ -n "$rid" ]] || continue
218
+ # </dev/null: the run-id herestring feeds the loop's stdin; a gh flag that ever read stdin
219
+ # would drain it. Same guard on the report() close loop below.
220
+ gh api --paginate "$RP/actions/runs/$rid/jobs?per_page=100" > "$WORK/jobs.json" 2>"$WORK/gh-err" </dev/null \
221
+ || die3 "gh api actions/runs/$rid/jobs failed: $(head -c 200 "$WORK/gh-err" | tr '\n' ' ')" api
222
+ jv=$(job_verdict "$CHECK" < "$WORK/jobs.json") \
223
+ || die3 "unparseable jobs response for main run $rid" parse
224
+ case "${jv%% *}" in
225
+ red|green) OUTCOME="${jv%% *}"; MAIN_RUN="$rid"; MAIN_CONCL="${jv#* }"; break ;;
226
+ none) ;;
227
+ esac
228
+ done <<<"$IDS_RAW"
229
+
230
+ case "$OUTCOME" in
231
+ red) VERDICT=red-on-main; RC=1 ;;
232
+ green) VERDICT=green-on-main; RC=0 ;;
233
+ *) VERDICT=no-evidence; RC=2 ;;
234
+ esac
235
+
236
+ # ── --report: sentinel-keyed issue file/dedupe/close ─────────────────────────────────────────
237
+ report() {
238
+ local SENTINEL="<!-- soleur:red-on-main check=\"$CHECK\" -->"
239
+ local rc=0 open_json
240
+ # rc captured separately: `|| true` would collapse "no tracker" and "API error" into the same
241
+ # empty string, and the filer would file a duplicate on a transient failure (#1357 lesson).
242
+ # No --search: the issue LIST api is strongly consistent, while search indexes a new issue
243
+ # seconds-to-minutes late — two probes close together could then each file a duplicate
244
+ # tracker. Mirrors main-health-monitor's idiom: list the labeled issues, filter the
245
+ # sentinel locally.
246
+ open_json=$(gh issue list "${REPO_ARG[@]}" --label "ci/main-broken" --state open \
247
+ --json number,body --limit 100) || rc=$?
248
+ if [[ "$rc" -ne 0 ]] || ! jq -e 'type == "array"' <<<"$open_json" >/dev/null 2>&1; then
249
+ echo "check-red-on-main: could not list ci/main-broken issues (rc=$rc) -- not filing or closing anything, to avoid acting on a transient error" >&2
250
+ return 0
251
+ fi
252
+
253
+ if [[ "$VERDICT" == red-on-main ]]; then
254
+ # OLDEST first: gh issue list returns created-DESC, so .[0] unsorted is the NEWEST -- an
255
+ # older tracker would be orphaned and keep the file-new arm unreachable forever.
256
+ local existing
257
+ existing=$(jq -r --arg s "$SENTINEL" \
258
+ '[.[] | select(.body | type == "string" and contains($s)) | .number] | sort | .[0] // empty' \
259
+ <<<"$open_json" 2>/dev/null) || existing=""
260
+ if [[ -n "$existing" ]]; then
261
+ # >/dev/null: gh prints the comment URL on stdout — the marker is the only stdout line.
262
+ gh issue comment "$existing" "${REPO_ARG[@]}" --body \
263
+ "Still red on main: check \`$CHECK\` concluded $MAIN_CONCL on main run $MAIN_RUN. (probe run: $RUN_ID)" \
264
+ >/dev/null || echo "check-red-on-main: could not comment on #$existing" >&2
265
+ echo "check-red-on-main: commented on existing sentinel tracker #$existing" >&2
266
+ return 0
267
+ fi
268
+ gh label create "ci/main-broken" --force "${REPO_ARG[@]}" >/dev/null 2>&1 || true
269
+ local url
270
+ url=$(gh issue create "${REPO_ARG[@]}" \
271
+ --title "Red on main: $CHECK" \
272
+ --body "$(printf '%s\n' \
273
+ "$SENTINEL" \
274
+ "" \
275
+ "Check \`$CHECK\` is failing on main." \
276
+ "" \
277
+ "- Newest exercising main run: $MAIN_RUN (conclusion: $MAIN_CONCL)" \
278
+ "- Observed failing on PR-side run: $RUN_ID" \
279
+ "" \
280
+ "Filed by check-red-on-main.sh --report: this check is quarantined for PR rerun/fix" \
281
+ "decisions while it is red on main. This tracker is auto-closed when the check goes" \
282
+ "green on main again — to verify/close, re-run" \
283
+ "\`check-red-on-main.sh \"$CHECK\" --run-id <any run id of this workflow> --report\`;" \
284
+ "a green verdict closes this issue.")" \
285
+ --label "ci/main-broken" --label "meta/machinery" --label "type/chore" \
286
+ --milestone "Post-MVP / Later" 2>/dev/null) || url=""
287
+ if [[ -n "$url" ]]; then
288
+ echo "check-red-on-main: filed tracker $url" >&2
289
+ else
290
+ echo "check-red-on-main: issue create failed -- the red-on-main verdict stands but no tracker was filed" >&2
291
+ fi
292
+ return 0
293
+ fi
294
+
295
+ # green-on-main: comment-and-close ONLY issues carrying OUR sentinel for this check name --
296
+ # every one of them, never a human-filed or other-sentinel tracker.
297
+ local mine n
298
+ mine=$(jq -r --arg s "$SENTINEL" \
299
+ '[.[] | select(.body | type == "string" and contains($s)) | .number] | sort | .[]' \
300
+ <<<"$open_json" 2>/dev/null) || mine=""
301
+ while IFS= read -r n; do
302
+ [[ -n "$n" ]] || continue
303
+ gh issue close "$n" "${REPO_ARG[@]}" --comment \
304
+ "Check \`$CHECK\` is green on main again (run $MAIN_RUN, conclusion $MAIN_CONCL). Auto-closing." \
305
+ >/dev/null </dev/null || echo "check-red-on-main: could not close #$n" >&2
306
+ echo "check-red-on-main: closed sentinel tracker #$n -- main is green again" >&2
307
+ done <<<"$mine"
308
+ return 0
309
+ }
310
+
311
+ if (( REPORT == 1 )) && [[ "$VERDICT" == red-on-main || "$VERDICT" == green-on-main ]]; then
312
+ report
313
+ fi
314
+
315
+ marker "$VERDICT"
316
+ exit "$RC"