@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,22 @@
1
+ # Pinned ruff for plugins/soleur/scripts/lint-ratchet.py (installed with pip --require-hashes --only-binary=:all:).
2
+ # Bump recipe: take the version and one sha256 per wheel from https://pypi.org/pypi/ruff/<version>/json,
3
+ # replace the pin and ALL hash lines below, then run: python3 plugins/soleur/scripts/lint-ratchet.py ruff --update
4
+ # (a hash line carries no trailing comment: pip rejects a continuation followed by one).
5
+ ruff==0.16.10 \
6
+ --hash=sha256:1dfc6f0088149fb6a362c1c446bcbb3fd2157b3852fe2fa68409276eab9ad9b3 \
7
+ --hash=sha256:25a65fe998c4e6861ec079ada5826a2fc605e6cbccbe9dcd7fac1f54e791621b \
8
+ --hash=sha256:2a12e01cb9156c10c466f63b46eaae5ecea28dfbd21b5836353ae498e7d1349a \
9
+ --hash=sha256:3031a4a2e8e7b8a46f70be45f198c35a11ece509a94b80334d8d397a33c67550 \
10
+ --hash=sha256:3e70175e29cc94c26ea296c80e470180b744b7419026898e58f520c6ab32578e \
11
+ --hash=sha256:488b0fe3f3574210e5cf80d9f59b9e3ab17a127a8155de3f307b392589cfb511 \
12
+ --hash=sha256:494401c86df4c4c25f69b9419605d944467ee98c42fb6ad405ef4fa40b8fb67d \
13
+ --hash=sha256:6553498afc35f580f036030795810b9e6bcea31604b0fd9e8d352795473042e3 \
14
+ --hash=sha256:7ae7375f803b5520dc9f546bed7e3a0acb70b91812e9bb4b19927de22f25b77d \
15
+ --hash=sha256:92e59a70bcbd9d3a5483656da906ec28edfdacfce00afd99edb8b4e9d15644be \
16
+ --hash=sha256:97f2015c92aa97105b0eab19eb5d224884399281cfc5da86a92db4ab5e7fb2ca \
17
+ --hash=sha256:a3b8471dea115d37f123882be852bed13403746d3a76c11de4a19ec5f9ff5a03 \
18
+ --hash=sha256:bc2610fb269fa56dd8a68669ae470fa6272902668c0fc2ebc3aa112b2633d5b8 \
19
+ --hash=sha256:bd83d1235a5258d318477bc5b576303974cbdef5df0c01a1bff14efcc23bd12a \
20
+ --hash=sha256:d203abc0ff2b773ee33d00ab8df0bb67046fbc7c07b119332f08b9b345cf8221 \
21
+ --hash=sha256:e748ff95c934c4e978783b8e687bc174e7bd84e8ad24e3243e1ecfcda5e0282d \
22
+ --hash=sha256:f33f43a864a8483eebd160e713336c8bab02c934feaff0a33cf5ccb41546d09a
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # run-in-pid-namespace.sh [--] <command> [args...]
3
+ #
4
+ # Runs <command> as PID 1 of a fresh PID namespace (own /proc), via
5
+ # unshare -Urpf --kill-child --mount-proc
6
+ # and REFUSES (rc 125, no unsandboxed fallback) when it cannot arrange that. Use it to run a
7
+ # MUTANT of any helper that signals processes: a helper that walks $PPID upward and signals the
8
+ # outermost ancestor whose argv matches is bounded only by its own match predicate, so a mutant
9
+ # of that predicate (-v, a dropped pattern, a catch-all) walks to the top of the user's session
10
+ # and ends it. Inside the namespace the command has no ancestor at all, so such a walk stops at
11
+ # the command itself. The incident this exists for: see
12
+ # knowledge-base/project/learnings/test-failures/2026-10-09-an-inverted-match-mutant-of-an-ancestor-walking-helper-ended-the-desktop-session-four-times.md
13
+ #
14
+ # Exit codes: the command's own code on success; 125 = refused (the command never started; the
15
+ # FIRST stderr line is "RUN_IN_PID_NAMESPACE_REFUSED reason=<missing-unshare|userns-unavailable|
16
+ # not-isolating> ..."; a wrapped command that itself exits 125 prints no such line, so a caller
17
+ # tells them apart by the marker, not the code); 2 = usage error.
18
+ #
19
+ # Trust anchor: PATH. The probe and the run use one absolute unshare, but sh, awk and the other tools
20
+ # resolve through the caller's PATH, so a caller who controls PATH controls them.
21
+ #
22
+ # What a PID namespace does NOT bound: filesystem writes (the mount namespace is created for
23
+ # /proc only), network, IPC, abstract unix sockets, the D-Bus session bus, path-based sockets under XDG_RUNTIME_DIR (hyprctl,
24
+ # tmux, sway/i3 IPC) and the session manager (loginctl terminate-session still reaches the host). The caller is mapped to uid 0
25
+ # inside, so id -u and root-guard branches differ. The command is PID 1 there, so a signal it
26
+ # sends ITSELF is ignored: bound a run with `timeout -k <grace> <secs> <this script> ...`, never
27
+ # a plain `timeout`. A backgrounded child does not outlive the command (--kill-child).
28
+ set -u
29
+
30
+ readonly MARKER=RUN_IN_PID_NAMESPACE_REFUSED
31
+
32
+ # Shared context-sanitize lib (#10395), beside this script under lib/. When it
33
+ # is unreadable the same-name fallback carries this site's pre-change strip set
34
+ # (C0+DEL) — never weaker than today.
35
+ _ctx_lib="$(cd "${BASH_SOURCE[0]%/*}" 2>/dev/null && pwd -P)/lib/context-sanitize.sh"
36
+ _ctx_lib="${_ctx_lib:-/nonexistent/context-sanitize.sh}"
37
+ # shellcheck source=/dev/null
38
+ [[ -r "$_ctx_lib" ]] && . "$_ctx_lib" || true
39
+ declare -F soleur_ctx_sanitize >/dev/null 2>&1 \
40
+ || soleur_ctx_sanitize() { LC_ALL=C tr -d '\000-\037\177'; }
41
+
42
+ [[ "${1:-}" == "--" ]] && shift
43
+ if [[ $# -eq 0 ]]; then
44
+ printf 'usage: %s [--] <command> [args...]\n' "${0##*/}" >&2
45
+ exit 2
46
+ fi
47
+ # `exec` reads a leading dash as an option, and `exec --` is not portable (dash, the sh of Debian and
48
+ # Ubuntu, rejects it), so a command word that begins with a dash is refused here, before anything
49
+ # starts. A file whose name begins with a dash runs when given as a path (./-name).
50
+ if [[ "$1" == -* ]]; then
51
+ printf '%s: the command must not begin with "-" (give a path such as ./%s)\n' "${0##*/}" "$1" >&2
52
+ exit 2
53
+ fi
54
+
55
+ # The isolation property, written ONCE and used by the probe and by the run: this shell is PID 1
56
+ # and /proc is the namespace's own (NSpid has exactly one field; a wrapper that drops
57
+ # --mount-proc keeps $$ at 1 but shows the host's process list, so $$ alone is not enough).
58
+ # shellcheck disable=SC2016 # the single quotes are intentional: this text runs inside the namespace
59
+ CHECK='[ "$$" = 1 ] && [ "$(awk "/^NSpid:/{print NF-1}" /proc/self/status 2>/dev/null)" = 1 ]'
60
+
61
+ refuse() { # reason cause remedy
62
+ {
63
+ printf '%s reason=%s\n' "$MARKER" "$1"
64
+ printf 'cause: %s\n' "$2"
65
+ printf 'remedy: %s\n' "$3"
66
+ printf 'no unsandboxed fallback: run the mutant on a host that allows user namespaces, or do not run it.\n'
67
+ } >&2
68
+ exit 125
69
+ }
70
+
71
+ # Resolve unshare ONCE to an absolute path: `type -P` consults PATH only, so a shell function or alias
72
+ # named unshare cannot decide the probe, a relative PATH entry is refused, and the probe and the run use
73
+ # the same binary.
74
+ u="$(type -P unshare 2>/dev/null || true)"
75
+ if [[ -z "$u" || "$u" != /* ]]; then
76
+ refuse missing-unshare "unshare (util-linux) was not found on PATH as an absolute path" \
77
+ "use a Linux host with util-linux; stock macOS has no unshare, so use a Linux VM"
78
+ fi
79
+
80
+ probe_err="$("$u" -Urpf --kill-child --mount-proc -- sh -c "$CHECK || exit 97" 2>&1 >/dev/null)"
81
+ probe_rc=$?
82
+ if [[ "$probe_rc" -ne 0 ]]; then
83
+ # One line, control characters stripped, cut short: the text comes from whatever unshare is.
84
+ first="$(printf '%s\n' "$probe_err" | head -n 1 | soleur_ctx_sanitize | cut -c1-200)"
85
+ if [[ "$probe_rc" -eq 97 ]]; then
86
+ refuse not-isolating "the unshare on PATH ran the command without a fresh PID namespace and its own /proc (or awk or /proc/self/status was unusable inside it)" \
87
+ "check which unshare resolves first on PATH and that it is util-linux unshare"
88
+ fi
89
+ refuse userns-unavailable "unshare failed (rc $probe_rc): ${first:-no message}" \
90
+ "run the mutant on a disposable VM or container that allows unprivileged user namespaces; enabling them on a workstation (sysctl kernel.unprivileged_userns_clone, kernel.apparmor_restrict_unprivileged_userns, user.max_user_namespaces) or allowing unshare in a container seccomp profile weakens that host, so do it only on a throwaway host. On a restricted CI runner every seat on a signalling helper refuses until the runner relaxes the sysctl"
91
+ fi
92
+
93
+ # The same check runs again inside the namespace right before the command (it keeps the property
94
+ # true at the instant of the exec even if the probe and this run disagreed). A plain `exec` (never
95
+ # `exec --`, which dash rejects) leaves the command as PID 1 with no ancestor; a command word that
96
+ # begins with a dash was refused above, so exec cannot read it as an option.
97
+ RUN="$CHECK || { printf '%s\\n' '$MARKER reason=not-isolating (re-check inside the namespace failed)' >&2; exit 125; }; exec \"\$@\""
98
+ exec "$u" -Urpf --kill-child --mount-proc -- sh -c "$RUN" sh "$@"
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env bash
2
+ # Tests for plugins/soleur/scripts/run-in-pid-namespace.sh: the helper that runs a command as PID 1 of
3
+ # a fresh PID namespace and REFUSES (rc 125, marker line, command never started) when it cannot.
4
+ #
5
+ # Two kinds of rows. ALWAYS-RUN rows use a stub `unshare` on a private PATH, so the helper's logic is
6
+ # proven on every host (CI shapes where user namespaces are restricted, macOS). REAL-NAMESPACE rows
7
+ # need working user namespaces; one probe decides, and where they are unavailable they are COUNTED as
8
+ # skipped (a SKIP line names how many and why) and the real helper's refusal is asserted instead (R8).
9
+ # SOLEUR_REQUIRE_REAL_NS=1 turns "unavailable" into a FAIL.
10
+ #
11
+ # The containment row (N4) never runs a lethal walker: it uses a nonce-scoped fixture walker
12
+ # (plugins/soleur/test/fixtures/ancestor-signal/walker-nonce.txt) that signals only ancestors whose
13
+ # argv carries a per-run 32-hex nonce, so even a helper that regressed to run in place could only
14
+ # reach the fixture's own `victim`.
15
+ #
16
+ # Run: bash plugins/soleur/scripts/run-in-pid-namespace.test.sh
17
+
18
+ # shellcheck disable=SC2319 # check() deliberately consumes the status of the condition on the line above
19
+ set -uo pipefail
20
+ export TMPDIR="${TMPDIR:-/var/tmp}"
21
+ unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE GIT_COMMON_DIR 2>/dev/null || true
22
+
23
+ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
24
+ SUT="$DIR/run-in-pid-namespace.sh"
25
+ WALKER="$DIR/../test/fixtures/ancestor-signal/walker-nonce.txt"
26
+ BASH_BIN="$(type -P bash)"
27
+
28
+ FIX="$(mktemp -d -t runinns.XXXXXXXX)" || { echo "FATAL: mktemp failed" >&2; exit 2; }
29
+ trap 'rm -rf "$FIX"' EXIT
30
+
31
+ # shellcheck source=../test/test-helpers.sh
32
+ source "$DIR/../test/test-helpers.sh" || { echo "FATAL: could not source test-helpers.sh" >&2; exit 2; }
33
+ set +e -uo pipefail
34
+ assert_fixture_dir "$FIX"
35
+ [[ -f "$SUT" ]] || { printf '[FATAL] SUT missing at %s\n' "$SUT" >&2; exit 1; }
36
+ [[ -f "$WALKER" ]] || { printf '[FATAL] walker fixture missing at %s\n' "$WALKER" >&2; exit 1; }
37
+
38
+ passes=0; fails=0; cases=0; skipped=0
39
+ FAILURES=()
40
+ ok() { passes=$((passes + 1)); printf ' ok: %s\n' "$1"; }
41
+ bad() { fails=$((fails + 1)); FAILURES+=("$1"); printf ' FAIL: %s\n' "$1"; }
42
+ check() { # description condition-result(0=true)
43
+ cases=$((cases + 1))
44
+ if [[ "$2" -eq 0 ]]; then ok "$1"; else bad "$1"; fi
45
+ }
46
+
47
+ # Instrument self-test: drive both verdict helpers once, require both counters to move, then unwind.
48
+ _p0=$passes; _f0=$fails; _c0=$cases; _l0=${#FAILURES[@]}
49
+ ok "selftest" >/dev/null; bad "selftest" >/dev/null
50
+ if [[ $passes -ne $((_p0 + 1)) || $fails -ne $((_f0 + 1)) ]]; then
51
+ printf 'FATAL: ok()/bad() do not record verdicts\n' >&2; exit 1
52
+ fi
53
+ passes=$_p0; fails=$_f0; cases=$_c0; FAILURES=()
54
+
55
+ # --- private PATHs ------------------------------------------------------------
56
+ mkdir -p "$FIX/nobin" "$FIX/stub"
57
+ assert_fixture_dir "$FIX"
58
+ for t in bash sh awk tr cut head cat env; do
59
+ src="$(type -P "$t" 2>/dev/null || true)"
60
+ [[ -n "$src" ]] && ln -sf "$src" "$FIX/nobin/$t"
61
+ done
62
+ REAL_UNSHARE="$(type -P unshare 2>/dev/null || true)"
63
+ W="$FIX/witness"
64
+
65
+ # run the helper with a private PATH; sets OUT (stdout+stderr) and RC
66
+ run_helper() { # path-dir cmd...
67
+ local pdir="$1"; shift
68
+ RC=0
69
+ OUT="$(PATH="$pdir" "$BASH_BIN" "$SUT" "$@" 2>&1)" || RC=$?
70
+ }
71
+ first_line() { printf '%s\n' "$1" | head -n 1; }
72
+ witness_cmd=(sh -c ': > "$1"' sh "$W")
73
+
74
+ mkstub() { # name body -- writes $FIX/stub/<name>/unshare
75
+ mkdir -p "$FIX/stub/$1"; assert_fixture_dir "$FIX"
76
+ printf '#!/bin/sh\n%s\n' "$2" > "$FIX/stub/$1/unshare"; chmod +x "$FIX/stub/$1/unshare"
77
+ for t in bash sh awk tr cut head cat env; do ln -sf "$FIX/nobin/$t" "$FIX/stub/$1/$t" 2>/dev/null || true; done
78
+ }
79
+
80
+ echo "=== always-run rows (stub unshare) ==="
81
+
82
+ # R6 witness control: the witness command, run directly, DOES create the witness.
83
+ rm -f "$W"; "${witness_cmd[@]}"
84
+ [[ -e "$W" ]]; check "R6 witness control: the witness command writes its file when it runs" $?
85
+ rm -f "$W"
86
+
87
+ # R1 unshare absent.
88
+ rm -f "$W"; run_helper "$FIX/nobin" "${witness_cmd[@]}"
89
+ [[ "$RC" -eq 125 && "$(first_line "$OUT")" == "RUN_IN_PID_NAMESPACE_REFUSED reason=missing-unshare"* && ! -e "$W" ]]
90
+ check "R1 no unshare on PATH: rc 125, marker reason=missing-unshare, command never started" $?
91
+
92
+ # R2 unshare fails (EPERM): rc 125, the stub's first line quoted on one line.
93
+ mkstub fail 'echo "unshare: unshare failed: Operation not permitted" >&2; exit 1'
94
+ rm -f "$W"; run_helper "$FIX/stub/fail" "${witness_cmd[@]}"
95
+ [[ "$RC" -eq 125 && "$(first_line "$OUT")" == "RUN_IN_PID_NAMESPACE_REFUSED reason=userns-unavailable"* && ! -e "$W" ]]
96
+ check "R2 failing unshare: rc 125, reason=userns-unavailable, command never started" $?
97
+ printf '%s\n' "$OUT" | grep -cF >/dev/null -- "Operation not permitted"
98
+ check "R2b the unshare message is quoted in the refusal" $?
99
+ [[ "$(printf '%s\n' "$OUT" | grep -c '^RUN_IN_PID_NAMESPACE_REFUSED')" -eq 1 ]]
100
+ check "R2c exactly one marker line" $?
101
+
102
+ # R3 dishonest unshare: exits 0 and runs the command in place.
103
+ mkstub dishonest 'while [ "$1" != "--" ]; do shift; done; shift; exec "$@"'
104
+ rm -f "$W"; run_helper "$FIX/stub/dishonest" "${witness_cmd[@]}"
105
+ [[ "$RC" -eq 125 && "$(first_line "$OUT")" == "RUN_IN_PID_NAMESPACE_REFUSED reason=not-isolating"* && ! -e "$W" ]]
106
+ check "R3 dishonest unshare (runs in place): rc 125, reason=not-isolating, command never started" $?
107
+
108
+ # R4 argv: a recording stub (lies on both calls by exiting 0 without running anything).
109
+ mkstub rec 'n=$(cat "'"$FIX"'/calln" 2>/dev/null || echo 0); n=$((n+1)); echo $n > "'"$FIX"'/calln"; printf "%s\n" "$@" > "'"$FIX"'/argv.$n"; exit 0'
110
+ rm -f "$FIX"/calln "$FIX"/argv.*; run_helper "$FIX/stub/rec" -- sh -c 'echo hi' x '' -n "a b"
111
+ [[ "$RC" -eq 0 && -s "$FIX/argv.2" ]]; check "R4 recording stub sees a probe call and a run call" $?
112
+ flags_ok=0
113
+ for f in -U -r -p -f --kill-child --mount-proc; do
114
+ # combined -Urpf is equivalent to the split spellings
115
+ if [[ "$f" == --* ]]; then
116
+ [[ "$(grep -cxF -- "$f" "$FIX/argv.2")" -eq 1 ]] || flags_ok=1
117
+ else
118
+ letter="${f#-}"
119
+ [[ "$(sed -n '1,/^--$/p' "$FIX/argv.2" | grep -E -- '^-[A-Za-z]+$' | grep -c "$letter")" -ge 1 ]] || flags_ok=1
120
+ fi
121
+ done
122
+ check "R4b all of -U -r -p -f --kill-child --mount-proc precede -- in the run call" "$flags_ok"
123
+ mapfile -t AV < "$FIX/argv.2"
124
+ di=-1; for i in "${!AV[@]}"; do [[ "${AV[$i]}" == "--" ]] && { di=$i; break; }; done
125
+ rest=""; if [[ "$di" -ge 0 ]]; then for ((i = di + 5; i < ${#AV[@]}; i++)); do rest+="${AV[$i]}|"; done; fi
126
+ [[ "$di" -ge 0 && "${AV[$((di + 1))]:-}" == "sh" && "${AV[$((di + 2))]:-}" == "-c" && "${AV[$((di + 3))]:-}" == *'; exec "$@"' && "${AV[$((di + 4))]:-}" == "sh" && "$rest" == 'sh|-c|echo hi|x||-n|a b|' ]]
127
+ check "R4c the whole argv after -- is sh -c <RUN ending exec \"\$@\"> sh then the command verbatim (spaces, an empty argument, a leading -n)" $?
128
+
129
+ # R11 a command word that begins with a dash is refused before anything starts (exec would read it as an
130
+ # option, and dash rejects exec --): rc 2, named message, no unshare call, command never started.
131
+ rm -f "$W" "$FIX"/calln "$FIX"/argv.*; run_helper "$FIX/stub/rec" -touch "$W"
132
+ [[ "$RC" -eq 2 && "$OUT" == *'must not begin with "-"'* && ! -e "$W" && ! -e "$FIX/calln" ]]
133
+ check "R11 a command beginning with a dash is refused: rc 2, no unshare call, never started" $?
134
+
135
+ # R5 usage.
136
+ run_helper "$FIX/nobin"
137
+ [[ "$RC" -eq 2 && "$OUT" == usage:* ]]; check "R5 no command: usage, rc 2" $?
138
+
139
+ # R7 the in-namespace re-check: the probe call lies (exit 0), the run call executes in place.
140
+ mkstub lateliar 'n=$(cat "'"$FIX"'/call7" 2>/dev/null || echo 0); n=$((n+1)); echo $n > "'"$FIX"'/call7"
141
+ if [ "$n" -eq 1 ]; then echo probe-isolated >> "'"$FIX"'/log7"; exit 0; fi
142
+ echo run-in-place >> "'"$FIX"'/log7"; while [ "$1" != "--" ]; do shift; done; shift; exec "$@"'
143
+ rm -f "$W" "$FIX"/call7 "$FIX"/log7; run_helper "$FIX/stub/lateliar" "${witness_cmd[@]}"
144
+ [[ "$RC" -eq 125 && "$OUT" == *"RUN_IN_PID_NAMESPACE_REFUSED reason=not-isolating"* && ! -e "$W" ]]
145
+ check "R7 the check inside the namespace refuses when the run is not isolated: rc 125, marker, command never started" $?
146
+ [[ "$(cat "$FIX/log7" 2>/dev/null | tr '\n' ' ')" == "probe-isolated run-in-place " ]]
147
+ check "R7b positive control: the stub took the isolated branch on the probe and the in-place branch on the run" $?
148
+
149
+ # R9 an exported function named unshare must not decide the probe: a failing unshare is on PATH, the function
150
+ # would succeed, and the refusal must come from the PATH binary.
151
+ rm -f "$W"
152
+ RC=0; OUT="$(unshare() { return 0; }; export -f unshare; PATH="$FIX/stub/fail" "$BASH_BIN" "$SUT" "${witness_cmd[@]}" 2>&1)" || RC=$?
153
+ [[ "$RC" -eq 125 && "$OUT" == "RUN_IN_PID_NAMESPACE_REFUSED reason=userns-unavailable"* && ! -e "$W" ]]
154
+ check "R9 an exported shell function unshare does not decide the probe (the PATH binary does)" $?
155
+
156
+ # R10 below: the helper must not refuse where the host itself can create the namespace.
157
+
158
+ # --- probe decides the real-namespace branch ---------------------------------
159
+ REAL_NS=no; REAL_WHY="no unshare on PATH"
160
+ if [[ -n "$REAL_UNSHARE" ]]; then
161
+ PROBE_OUT="$("$BASH_BIN" "$SUT" sh -c 'echo ok' 2>&1)"; PROBE_RC=$?
162
+ if [[ "$PROBE_RC" -eq 0 && "$PROBE_OUT" == "ok" ]]; then REAL_NS=yes
163
+ else REAL_WHY="$(first_line "$PROBE_OUT" | cut -c1-120)"; fi
164
+ fi
165
+
166
+ # An INDEPENDENT host probe (the SUT is not involved): where the host can create the namespace and the helper
167
+ # still refuses, the helper is broken, and that must be a FAIL, never a SKIP.
168
+ HOST_NS=no
169
+ if [[ -n "$REAL_UNSHARE" ]]; then
170
+ HOST_OUT="$("$REAL_UNSHARE" -Urpf --kill-child --mount-proc -- sh -c 'echo ok' 2>&1)"; HOST_RC=$?
171
+ [[ "$HOST_RC" -eq 0 && "$HOST_OUT" == "ok" ]] && HOST_NS=yes
172
+ fi
173
+ [[ "$HOST_NS" != "yes" || "$REAL_NS" == "yes" ]]
174
+ check "R10 the helper does not refuse where the host itself can create the namespace (host=$HOST_NS, helper=$REAL_NS)" $?
175
+
176
+ if [[ "$REAL_NS" == "yes" ]]; then
177
+ echo "=== real-namespace rows ==="
178
+ # N1 PID 1, no parent, own /proc.
179
+ OUT="$("$BASH_BIN" "$SUT" sh -c 'echo "$$ $PPID $(awk "/^NSpid:/{print NF-1}" /proc/self/status)"' 2>&1)"
180
+ [[ "$OUT" == "1 0 1" ]]; check "N1 the command is PID 1 with PPID 0 and its own /proc" $?
181
+ # N2 exit codes pass through; a wrapped 125 carries no marker.
182
+ "$BASH_BIN" "$SUT" sh -c 'exit 0'; r0=$?; "$BASH_BIN" "$SUT" sh -c 'exit 3'; r3=$?
183
+ OUT="$("$BASH_BIN" "$SUT" sh -c 'exit 125' 2>&1)"; r125=$?
184
+ [[ "$r0" -eq 0 && "$r3" -eq 3 ]]; check "N2 exit codes 0 and 3 pass through" $?
185
+ [[ "$r125" -eq 125 && "$OUT" != *RUN_IN_PID_NAMESPACE_REFUSED* ]]; check "N2b a wrapped command's own 125 passes through with no marker" $?
186
+ # N3 stdin, stdout, stderr, cwd; a dash-leading command name.
187
+ mkdir -p "$FIX/cwd"; assert_fixture_dir "$FIX"
188
+ OUT="$(cd "$FIX/cwd" && printf 'in\n' | "$BASH_BIN" "$SUT" sh -c 'read x; echo "out:$x:$(pwd)"; echo err >&2' 2>"$FIX/err3")"
189
+ [[ "$OUT" == "out:in:$FIX/cwd" && "$(cat "$FIX/err3")" == "err" ]]
190
+ check "N3 stdin, stdout, stderr and cwd pass through, nothing added on stderr" $?
191
+ cat > "$FIX/-dashcmd" <<'EOS'
192
+ #!/bin/sh
193
+ echo dash-ran
194
+ EOS
195
+ chmod +x "$FIX/-dashcmd"
196
+ OUT="$(cd "$FIX" && "$BASH_BIN" "$SUT" -- ./-dashcmd 2>&1)"
197
+ [[ "$OUT" == "dash-ran" ]]; check "N3b a command whose file name begins with a dash runs when given as a path (./-name)" $?
198
+ # N4 containment: victim (outside, argv carries the nonce) -> helper -> top (PID 1, nonce) -> mid (nonce) -> walker.
199
+ NONCE="$(od -An -tx1 -N16 /dev/urandom | tr -d ' \n')"
200
+ [[ "$NONCE" =~ ^[0-9a-f]{32}$ ]]; check "N4 precondition: the nonce is 32 hex characters" $?
201
+ assert_fixture_dir "$FIX"
202
+ cat > "$FIX/top.sh" <<'EOS'
203
+ #!/bin/sh
204
+ sh "$FIX_DIR/mid.sh" "mid-$1"
205
+ echo top-done > "$FIX_DIR/top-done"
206
+ EOS
207
+ cat > "$FIX/mid.sh" <<'EOS'
208
+ #!/bin/sh
209
+ echo mid-started > "$FIX_DIR/mid-started"
210
+ sh "$WALKER_PATH"
211
+ echo mid-survived > "$FIX_DIR/mid-survived"
212
+ EOS
213
+ rm -f "$FIX/mid-started" "$FIX/mid-survived" "$FIX/top-done" "$FIX/victim-survived"
214
+ FIX_DIR="$FIX" WALKER_PATH="$WALKER" WALKER_NONCE="$NONCE" SOLEUR_TEST_SUITE_PID=$$ VOUT="$FIX/victim-survived" \
215
+ timeout -k 5 60 "$BASH_BIN" -c '"$@"; echo victim-survived > "$VOUT"' "victim-$NONCE" \
216
+ "$BASH_BIN" "$SUT" sh "$FIX/top.sh" "top-$NONCE" > "$FIX/n4.out" 2>&1
217
+ [[ -e "$FIX/mid-started" && ! -e "$FIX/mid-survived" ]]
218
+ check "N4b positive control: the walker signalled the in-namespace middle process (it started, and died before its next line)" $?
219
+ [[ -e "$FIX/top-done" && -e "$FIX/victim-survived" ]]
220
+ check "N4c containment: PID 1 of the namespace finished and the outside ancestor carrying the nonce survived" $?
221
+ # Fail-closed preconditions of the fixture walker, rehearsed with kill replaced by echo on the host chain.
222
+ for pre in empty-nonce short-nonce nonhex-nonce unset-suite; do
223
+ case "$pre" in
224
+ empty-nonce) n=""; sp=$$ ;;
225
+ short-nonce) n="abc123"; sp=$$ ;;
226
+ nonhex-nonce) n="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"; sp=$$ ;;
227
+ unset-suite) n="$NONCE"; sp="" ;;
228
+ esac
229
+ O="$(WALKER_KILL=echo WALKER_NONCE="$n" SOLEUR_TEST_SUITE_PID="$sp" "$BASH_BIN" -c 'sh "$1"' "carrier-$n" "$WALKER" 2>&1)"
230
+ [[ -z "$O" ]]; check "N4d the fixture walker signals nothing: $pre" $?
231
+ done
232
+ O="$(WALKER_KILL=echo WALKER_NONCE="$NONCE" SOLEUR_TEST_SUITE_PID=$$ "$BASH_BIN" -c 'echo $$ > "$2"; sh "$1"; :' "carrier-$NONCE" "$WALKER" "$FIX/carrier.pid" 2>&1)"
233
+ [[ "$O" == "-TERM $(cat "$FIX/carrier.pid" 2>/dev/null)" ]]
234
+ check "N4e rehearsal with kill replaced by echo targets exactly the nonce-carrying ancestor, nothing above it" $?
235
+ # N5 a backgrounded child is gone after the helper returns; N5b the same after the helper is SIGKILLed.
236
+ has_proc() { # tag -> 0 when some process cmdline carries the tag (the bracket keeps this grep's own argv from matching)
237
+ grep -alqE -- "[${1:0:1}]${1:1}" /proc/[0-9]*/cmdline 2>/dev/null
238
+ }
239
+ T5="bgtag-$NONCE"
240
+ "$BASH_BIN" "$SUT" "$BASH_BIN" -c 'exec -a "$1" sleep 40 & exit 0' sh "$T5" >/dev/null 2>&1
241
+ gone=1; for _ in 1 2 3 4 5 6 7 8 9 10; do has_proc "$T5" || { gone=0; break; }; sleep 0.2; done
242
+ check "N5 a backgrounded child does not outlive the command (the helper returned)" "$gone"
243
+ T5b="bgkill-$NONCE"
244
+ "$BASH_BIN" "$SUT" "$BASH_BIN" -c 'exec -a "$1" sleep 40' sh "$T5b" >/dev/null 2>&1 &
245
+ hp=$!
246
+ up=1; for _ in 1 2 3 4 5 6 7 8 9 10; do has_proc "$T5b" && { up=0; break; }; sleep 0.2; done
247
+ [[ "$up" -eq 0 ]]; check "N5b control: the tagged child is running while the helper runs" $?
248
+ kill -KILL "$hp" 2>/dev/null; wait "$hp" 2>/dev/null
249
+ gone=1; for _ in 1 2 3 4 5 6 7 8 9 10; do has_proc "$T5b" || { gone=0; break; }; sleep 0.2; done
250
+ check "N5c SIGKILL of the helper reaps the tree (--kill-child)" "$gone"
251
+ # N6 nested use.
252
+ OUT="$("$BASH_BIN" "$SUT" "$BASH_BIN" "$SUT" sh -c 'echo "$$ $PPID"' 2>&1)"
253
+ [[ "$OUT" == "1 0" ]]; check "N6 a nested helper call works" $?
254
+ # N7 a wrapper unshare that drops --mount-proc is refused.
255
+ mkdir -p "$FIX/stub/noproc"; assert_fixture_dir "$FIX"
256
+ cat > "$FIX/stub/noproc/unshare" <<EOS
257
+ #!/bin/sh
258
+ for x; do shift; [ "\$x" = "--mount-proc" ] || set -- "\$@" "\$x"; done
259
+ exec $REAL_UNSHARE "\$@"
260
+ EOS
261
+ chmod +x "$FIX/stub/noproc/unshare"
262
+ for t in bash sh awk tr cut head cat env; do ln -sf "$FIX/nobin/$t" "$FIX/stub/noproc/$t" 2>/dev/null || true; done
263
+ rm -f "$W"; run_helper "$FIX/stub/noproc" "${witness_cmd[@]}"
264
+ [[ "$RC" -eq 125 && "$OUT" == *"reason=not-isolating"* && ! -e "$W" ]]
265
+ check "N7 a wrapper that drops --mount-proc is refused (host /proc has two NSpid fields)" $?
266
+ else
267
+ # R8: where namespaces are unavailable the REAL helper must still refuse.
268
+ echo "SKIP real-namespace rows: user namespaces unavailable here ($REAL_WHY)"
269
+ skipped=$((skipped + 18)) # the 18 real-namespace rows: N1 N2 N2b N3 N3b N4 N4b N4c N4d x4 N4e N5 N5b N5c N6 N7
270
+ rm -f "$W"; RC=0; OUT="$("$BASH_BIN" "$SUT" "${witness_cmd[@]}" 2>&1)" || RC=$?
271
+ [[ "$RC" -eq 125 && "$(first_line "$OUT")" == "RUN_IN_PID_NAMESPACE_REFUSED reason="* && ! -e "$W" ]]
272
+ check "R8 the real helper refuses (rc 125, marker, command never started) where namespaces are unavailable" $?
273
+ if [[ "${SOLEUR_REQUIRE_REAL_NS:-}" == "1" ]]; then check "SOLEUR_REQUIRE_REAL_NS=1 but user namespaces are unavailable ($REAL_WHY)" 1; fi
274
+ fi
275
+
276
+ # --- verdict ------------------------------------------------------------------
277
+ echo ""
278
+ printf '=== run-in-pid-namespace: %d passed, %d failed (%d cases, %d skipped, real-namespace=%s) ===\n' "$passes" "$fails" "$cases" "$skipped" "$REAL_NS"
279
+ if [[ "$REAL_NS" != "yes" ]]; then printf 'SKIP: %d real-namespace rows (%s)\n' "$skipped" "$REAL_WHY"; fi
280
+ for f in ${FAILURES[@]+"${FAILURES[@]}"}; do printf ' - %s\n' "$f"; done
281
+ # Anti-vacuity floors: literal thresholds on the line above each test, reported by printf, appended to the ledger the verdict reads.
282
+ if [[ "$cases" -lt 16 ]]; then printf 'FAIL: vacuity floor: only %d cases ran (>= 16 always-run rows expected, R8 counted when namespaces are unavailable)\n' "$cases" >&2; FAILURES+=("always-run floor"); fi
283
+ if [[ "$REAL_NS" == "yes" ]]; then
284
+ if [[ "$cases" -lt 33 ]]; then printf 'FAIL: vacuity floor: only %d cases ran (>= 33 expected with real namespaces)\n' "$cases" >&2; FAILURES+=("real-namespace floor"); fi
285
+ if [[ "$cases" -ne 33 ]]; then printf 'FAIL: conservation: %d cases ran, 33 planned with real namespaces\n' "$cases" >&2; FAILURES+=("planned total"); fi
286
+ else
287
+ if [[ "$((cases + skipped))" -ne 34 ]]; then printf 'FAIL: conservation: %d cases + %d skipped != 34 planned\n' "$cases" "$skipped" >&2; FAILURES+=("planned total"); fi
288
+ fi
289
+ if [[ "$((passes + fails))" -ne "$cases" ]]; then printf 'FAIL: verdict conservation: %d passes + %d fails != %d cases\n' "$passes" "$fails" "$cases" >&2; FAILURES+=("conservation"); fi
290
+ [[ "${#FAILURES[@]}" -eq 0 ]]