@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,785 @@
1
+ #!/usr/bin/env bash
2
+ # verification-scaffold — deterministic generator for the generic guardrail set
3
+ # (#10404). Iterates references/guards.tsv (tier=v1) and emits the selected
4
+ # guards into a user repo: PreToolUse hooks + a .claude/settings.json merge +
5
+ # scripts/verification/ helpers + a repo-root .github/workflows/verification-
6
+ # gates.yml, advisory-first by default. A TMPDIR-detached-worktree bite-proof
7
+ # proves each installed guard pass -> fail -> pass before the doc block is
8
+ # written.
9
+ #
10
+ # Usage:
11
+ # verification-scaffold.sh [--target PATH] [--guards a,b | --all]
12
+ # [--mode advisory|enforce] [--dry-run] [--list]
13
+ # [--uninstall GUARD] [--headless]
14
+ #
15
+ # Defaults: --target $PWD, --guards = all v1 rows, --mode advisory, interactive
16
+ # is a no-op (--headless only declares the intent — the script never prompts).
17
+ #
18
+ # Exit matrix (every non-zero is a hard, fail-closed stop; every message prints
19
+ # on STDOUT first — agent runtimes surface stdout and swallow stderr):
20
+ # 0 success (incl. --uninstall of a never-installed guard: prints, exits 0)
21
+ # 64 usage error (unknown flag, unknown/v2 guard, --mode bogus)
22
+ # 65 precondition: --target is not inside a git work tree
23
+ # 66 refuse-if-exists (an emitted artifact already present; NO --force)
24
+ # 69 TMPDIR resolves inside the target, neither node nor jq resolves, the
25
+ # existing .claude/settings.json is malformed, a git error, or the run
26
+ # lock is held (<git-common-dir>/verification-scaffold.lock, pid inside)
27
+ # 71 bite-proof: an installed guard did not pass on the clean staged tree
28
+ # 72 bite-proof: an installed guard did NOT decide on the injected probe
29
+ # 73 bite-proof: an installed guard did not return to green after the probe
30
+ #
31
+ # Self-cleanup: armed BEFORE the first write, disarmed after the bite passes —
32
+ # every failure in between removes exactly the artifacts THIS run emitted
33
+ # (tracked in $WORK/emitted + the settings.json backup), so a failed install is
34
+ # re-runnable and never leaves a half-installed guard set. The doc block is
35
+ # written last; a doc failure warns only.
36
+ #
37
+ # Portable: POSIX tools only (no realpath, no `sed -i`, timeout->gtimeout->bare
38
+ # fallback); runs on founder hosts including stock macOS.
39
+ set -euo pipefail
40
+
41
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
42
+ SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
43
+ REF_DIR="$SKILL_DIR/references"
44
+ GUARDS_TSV="$REF_DIR/guards.tsv"
45
+
46
+ TAG="verification-scaffold"
47
+ log() { printf '%s: %s\n' "$TAG" "$*" >&2; }
48
+ say() { printf '%s: %s\n' "$TAG" "$*"; }
49
+ warn() { printf '%s: WARNING: %s\n' "$TAG" "$*"; }
50
+ die() { say "FAILED (${2:-1}): $1"; log "$1"; exit "${2:-1}"; }
51
+
52
+ # physdir <dir>: physical path of an EXISTING directory (pwd -P — no realpath on
53
+ # stock macOS). Prints nothing when the dir is missing.
54
+ physdir() { ( cd -- "$1" 2>/dev/null && pwd -P ); }
55
+
56
+ # --- guards.tsv ---------------------------------------------------------------
57
+ # Row: name \t verdict \t surfaces \t templates \t default_mode \t deps \t
58
+ # source_files \t emits \t tier. Read once into parallel scalars via per-row
59
+ # helpers (small fixed set — a line-scan per lookup is fine and keeps bash 3.2
60
+ # compatibility: no associative arrays).
61
+ _guard_field() { # _guard_field <name> <col> -> field value (empty when absent)
62
+ awk -F'\t' -v n="$1" -v c="$2" '$1 == n { print $c; exit }' "$GUARDS_TSV"
63
+ }
64
+ v1_guards() { awk -F'\t' '$1 !~ /^#/ && $1 != "name" && $9 == "v1" { print $1 }' "$GUARDS_TSV"; }
65
+
66
+ # --- args ---------------------------------------------------------------------
67
+ TARGET="$PWD"
68
+ GUARDS_ARG=""
69
+ MODE="advisory"
70
+ DRY_RUN=0
71
+ DO_LIST=0
72
+ UNINSTALL=""
73
+ HEADLESS=0
74
+ while [[ $# -gt 0 ]]; do
75
+ case "$1" in
76
+ --target) TARGET="${2:-}"; shift 2 ;;
77
+ --guards) GUARDS_ARG="${2:-}"; shift 2 ;;
78
+ --all) GUARDS_ARG=""; shift ;;
79
+ --mode) MODE="${2:-}"; shift 2 ;;
80
+ --dry-run) DRY_RUN=1; shift ;;
81
+ --list) DO_LIST=1; shift ;;
82
+ --uninstall) UNINSTALL="${2:-}"; shift 2 ;;
83
+ --headless) HEADLESS=1; shift ;;
84
+ -h|--help) sed -n '2,20p' "$0"; exit 0 ;;
85
+ *) die "unknown argument: $1" 64 ;;
86
+ esac
87
+ done
88
+ case "$MODE" in advisory|enforce) ;; *) die "--mode must be advisory|enforce, got: $MODE" 64 ;; esac
89
+
90
+ # Resolve the guard set.
91
+ if [[ -n "$GUARDS_ARG" ]]; then
92
+ GUARDS="$(printf '%s' "$GUARDS_ARG" | tr ',' ' ')"
93
+ else
94
+ GUARDS="$(v1_guards | tr '\n' ' ')"
95
+ fi
96
+ GUARDS="${GUARDS% }"
97
+
98
+ for g in $GUARDS; do
99
+ tier="$(_guard_field "$g" 9)"
100
+ [[ -n "$tier" ]] || die "unknown guard: $g (run --list)" 64
101
+ [[ "$tier" == "v1" ]] || die "guard $g is a v2 candidate only — not emittable" 64
102
+ done
103
+ [[ -n "$UNINSTALL" ]] && { tier="$(_guard_field "$UNINSTALL" 9)"; [[ -n "$tier" ]] || die "unknown guard: $UNINSTALL" 64; }
104
+
105
+ # Target must resolve to a git work tree BEFORE anything else (SpecFlow #2).
106
+ TARGET="$(physdir "$TARGET")" || TARGET=""
107
+ [[ -n "$TARGET" ]] || die "--target does not resolve to a directory" 65
108
+ if [[ "$DO_LIST" -eq 0 ]]; then
109
+ git -C "$TARGET" rev-parse --is-inside-work-tree >/dev/null 2>&1 \
110
+ || die "target $TARGET is not inside a git work tree" 65
111
+ TARGET="$(physdir "$(git -C "$TARGET" rev-parse --show-toplevel)")"
112
+ fi
113
+
114
+ # --- --list ---------------------------------------------------------------------
115
+ if [[ "$DO_LIST" -eq 1 ]]; then
116
+ awk -F'\t' '$1 !~ /^#/ && $1 != "name" { printf "%-14s %-4s %-7s emits: %s\n", $1, $9, $3, $8 }' "$GUARDS_TSV"
117
+ if [[ -n "$TARGET" && -d "$TARGET/.git" || -f "$TARGET/.git" ]]; then
118
+ for g in $GUARDS; do
119
+ inst=""
120
+ IFS=';' read -ra ep <<<"$(_guard_field "$g" 8)"
121
+ for p in "${ep[@]}"; do [[ -e "$TARGET/$p" ]] && { inst="$inst $p"; }; done
122
+ [[ -n "$inst" ]] && say "installed:$g →${inst}"
123
+ done
124
+ fi
125
+ exit 0
126
+ fi
127
+
128
+ # --- run lock (mkdir in the git common dir) -------------------------------------
129
+ RUN_LOCK=""
130
+ take_run_lock() {
131
+ local common
132
+ common="$(git -C "$TARGET" rev-parse --git-common-dir 2>/dev/null)" || common=".git"
133
+ [[ "$common" == /* ]] || common="$TARGET/$common"
134
+ RUN_LOCK="$common/verification-scaffold.lock"
135
+ if ! mkdir "$RUN_LOCK" 2>/dev/null; then
136
+ local owner
137
+ owner="$(cat "$RUN_LOCK/pid" 2>/dev/null || true)"
138
+ if [[ -n "$owner" ]] && kill -0 "$owner" 2>/dev/null; then
139
+ RUN_LOCK=""
140
+ die "another verification-scaffold run (pid $owner) is in progress in this repository; wait for it" 69
141
+ fi
142
+ rm -rf -- "$RUN_LOCK"
143
+ mkdir "$RUN_LOCK" 2>/dev/null || { RUN_LOCK=""; die "cannot take the run lock at $RUN_LOCK" 69; }
144
+ fi
145
+ printf '%s\n' "$$" > "$RUN_LOCK/pid"
146
+ }
147
+ release_run_lock() {
148
+ [[ -n "${RUN_LOCK:-}" && -d "$RUN_LOCK" ]] && rm -rf -- "$RUN_LOCK"
149
+ RUN_LOCK=""
150
+ return 0
151
+ }
152
+
153
+ # TMPDIR containment — a mktemp inside the repo would land the bite worktree and
154
+ # its logs in the user's tree as untracked files (constraint-scaffold exit-69
155
+ # precedent).
156
+ check_tmpdir_outside_repo() {
157
+ local t
158
+ t="$(physdir "${TMPDIR:-/tmp}")" || t=""
159
+ [[ -n "$t" ]] || return 0
160
+ case "$t" in
161
+ "$TARGET"|"$TARGET"/*)
162
+ die "TMPDIR ($t) resolves inside the target repository; refusing" 69 ;;
163
+ esac
164
+ }
165
+
166
+ # --- emitted-file bookkeeping + self-cleanup -------------------------------------
167
+ WORK="$(mktemp -d -t verification-scaffold-XXXXXX)"
168
+ EMITTED_LOG="$WORK/emitted" # one target-absolute path per line, as written
169
+ DIRS_LOG="$WORK/dirs-created" # dirs mkdir -p created THIS run (deepest first)
170
+ : > "$EMITTED_LOG"; : > "$DIRS_LOG"
171
+ # Remove the bookkeeping dir on every pre-arm exit (early dies, --dry-run,
172
+ # --uninstall). The fuller _vs_cleanup trap replaces this at the arming site.
173
+ trap 'rm -rf -- "$WORK"' EXIT
174
+
175
+ record_emit() { printf '%s\n' "$1" >> "$EMITTED_LOG"; }
176
+ record_dir() { grep -qxF "$1" "$DIRS_LOG" 2>/dev/null || printf '%s\n' "$1" >> "$DIRS_LOG"; }
177
+
178
+ ensure_dir() { # ensure_dir <abs dir> — mkdir -p, recording only NEW dirs (leaf-up)
179
+ local d="$1" missing=""
180
+ while [[ ! -d "$d" ]]; do missing="$d $missing"; d="$(dirname "$d")"; done
181
+ for d in $missing; do mkdir "$d" && record_dir "$d"; done
182
+ }
183
+
184
+ SETTINGS="$TARGET/.claude/settings.json"
185
+ SETTINGS_BACKED_UP=0
186
+ backup_settings() {
187
+ [[ "$SETTINGS_BACKED_UP" -eq 1 ]] && return 0
188
+ if [[ -f "$SETTINGS" ]]; then cp "$SETTINGS" "$WORK/settings.json.bak"; else : > "$WORK/settings.json.absent"; fi
189
+ SETTINGS_BACKED_UP=1
190
+ }
191
+
192
+ CLEANUP_ARMED=0
193
+ _vs_cleanup() {
194
+ local why="${1:-run aborted}"
195
+ release_run_lock
196
+ if [[ "$CLEANUP_ARMED" -eq 1 ]]; then
197
+ local removed="" f d
198
+ while IFS= read -r f; do
199
+ [[ -e "$f" ]] && { rm -f -- "$f"; removed="$removed ${f#"$TARGET"/}"; }
200
+ done < "$EMITTED_LOG"
201
+ if [[ "$SETTINGS_BACKED_UP" -eq 1 ]]; then
202
+ if [[ -f "$WORK/settings.json.bak" ]]; then cp "$WORK/settings.json.bak" "$SETTINGS" && removed="$removed .claude/settings.json(restored)"
203
+ else rm -f -- "$SETTINGS" && removed="$removed .claude/settings.json"; fi
204
+ fi
205
+ # DIRS_LOG is recorded shallowest-first; remove deepest-first via a portable
206
+ # reverse (neither tac nor tail -r exists on both GNU and BSD).
207
+ while IFS= read -r d; do rmdir "$d" >/dev/null 2>&1 || true; done \
208
+ < <(awk '{a[NR]=$0} END{for(i=NR;i>0;i--)print a[i]}' "$DIRS_LOG")
209
+ [[ -n "$removed" ]] && say "$why; removed:${removed}"
210
+ fi
211
+ # The bite worktree is removed on the same path — a mid-bite failure must not
212
+ # leave a registered worktree behind.
213
+ if [[ -n "${WT:-}" && -d "$WT" ]]; then
214
+ git -C "$TARGET" worktree remove --force "$WT" >/dev/null 2>&1 || true
215
+ rm -rf -- "$WT"
216
+ fi
217
+ [[ -n "${BITE_DIR:-}" && -d "$BITE_DIR" ]] && rm -rf -- "$BITE_DIR"
218
+ rm -rf -- "$WORK"
219
+ return 0
220
+ }
221
+
222
+ # --- template emission -----------------------------------------------------------
223
+ # emit_tpl <template-rel> <target-rel> <mode>: render @MODE@/@DEFAULT_BRANCHES@/
224
+ # @CI_CONTINUE_ON_ERROR@ substitutions, write, record. Substitution is bash
225
+ # parameter expansion — a literal-replacement pass with no delimiter: under sed
226
+ # an unescaped `&` in DEFAULT_BRANCHES re-inserted the literal placeholder
227
+ # (fail-open: the emitted regex then never matched the real default branch) and
228
+ # sed's replacement layer ate the regex escapes outright (#10759).
229
+ emit_tpl() {
230
+ local tpl="$REF_DIR/$1" out="$TARGET/$2" mode="${3:-0644}"
231
+ ensure_dir "$(dirname "$out")"
232
+ local content
233
+ content="$(cat "$tpl")"
234
+ content="${content//@MODE@/$MODE}"
235
+ content="${content//@DEFAULT_BRANCHES@/$DEFAULT_BRANCHES}"
236
+ content="${content//@CI_CONTINUE_ON_ERROR@/$CI_CONTINUE_ON_ERROR}"
237
+ printf '%s\n' "$content" > "$out"
238
+ chmod "$mode" "$out"
239
+ record_emit "$out"
240
+ }
241
+
242
+ HOOK_COMMANDS=() # settings.json command strings, one per emitted hook
243
+ emit_guard() {
244
+ local g="$1"
245
+ case "$g" in
246
+ secret-scan)
247
+ emit_tpl "guards/secret-scan-hook.sh.template" ".claude/hooks/secret-scan.sh" 0755
248
+ HOOK_COMMANDS+=("bash \"\$CLAUDE_PROJECT_DIR/.claude/hooks/secret-scan.sh\"")
249
+ emit_tpl "gitleaks.toml.template" ".gitleaks.toml" 0644
250
+ ;;
251
+ commit-on-main)
252
+ emit_tpl "guards/commit-on-main-hook.sh.template" ".claude/hooks/commit-on-main.sh" 0755
253
+ HOOK_COMMANDS+=("bash \"\$CLAUDE_PROJECT_DIR/.claude/hooks/commit-on-main.sh\"")
254
+ emit_tpl "guards/precommit-guard.sh.template" "scripts/verification/precommit-guard.sh" 0755
255
+ emit_tpl "guards/wrapper-boundary.sh.template" "scripts/verification/lib/wrapper-boundary.sh" 0644
256
+ ;;
257
+ block-stash)
258
+ emit_tpl "guards/block-stash-hook.sh.template" ".claude/hooks/block-stash.sh" 0755
259
+ HOOK_COMMANDS+=("bash \"\$CLAUDE_PROJECT_DIR/.claude/hooks/block-stash.sh\"")
260
+ ;;
261
+ orphan-test)
262
+ emit_tpl "guards/orphan-test-check.sh.template" "scripts/verification/orphan-test-check.sh" 0755
263
+ emit_known_orphans
264
+ ;;
265
+ *) die "no emitter for guard: $g" 64 ;;
266
+ esac
267
+ }
268
+
269
+ # Seed .github/verification-known-orphans.txt: header + one grandfathered row per
270
+ # currently-unregistered tracked *.test.sh (the baseline precedent — pre-existing
271
+ # orphans are recorded, never silently absorbed).
272
+ RUNNER_GLOBS_SEED="scripts/test-all.sh scripts/run-tests* Makefile makefile package.json"
273
+ emit_known_orphans() {
274
+ local out="$TARGET/.github/verification-known-orphans.txt"
275
+ {
276
+ printf '# verification-known-orphans.txt — seeded by soleur:verification-scaffold.\n'
277
+ printf '# Format: <repo-relative path>.test.sh # <reason>. A suite listed here is\n'
278
+ printf '# excluded from the orphan-test check; a line without a reason fails it.\n'
279
+ } > "$out"
280
+ # Registration surfaces, same rule the emitted check applies: any workflow
281
+ # file plus any file matching a runner glob.
282
+ local surfaces="" f pat
283
+ for f in "$TARGET"/.github/workflows/*.yml "$TARGET"/.github/workflows/*.yaml; do
284
+ [[ -f "$f" ]] && surfaces="$surfaces $f"
285
+ done
286
+ local rf
287
+ while IFS= read -r rf; do surfaces="$surfaces $TARGET/$rf"; done < <(
288
+ cd "$TARGET" && for pat in $RUNNER_GLOBS_SEED; do for f in $pat; do [[ -f "$f" ]] && printf '%s\n' "$f"; done; done
289
+ )
290
+ local suite base seeded=0
291
+ while IFS= read -r suite; do
292
+ [[ -n "$suite" ]] || continue
293
+ base="$(basename "$suite")"
294
+ # shellcheck disable=SC2086
295
+ if [[ -n "${surfaces# }" ]] && grep -q . < <(grep -lFq -- "$base" $surfaces 2>/dev/null); then continue; fi
296
+ printf '%s # pre-existing at verification-scaffold install (grandfathered — register or remove)\n' "$suite" >> "$out"
297
+ seeded=$((seeded + 1))
298
+ done < <(git -C "$TARGET" ls-files '*.test.sh' 2>/dev/null)
299
+ [[ "$seeded" -gt 0 ]] && log "seeded $seeded grandfathered orphan row(s) in ${out#"$TARGET"/}"
300
+ record_emit "$out"
301
+ }
302
+
303
+ # --- settings.json merge (node-first, jq fallback, else refuse) -------------------
304
+ merge_settings() {
305
+ backup_settings
306
+ ensure_dir "$(dirname "$SETTINGS")"
307
+ local cmds=() h
308
+ for h in "${HOOK_COMMANDS[@]+"${HOOK_COMMANDS[@]}"}"; do [[ -n "$h" ]] && cmds+=("$h"); done
309
+ if command -v node >/dev/null 2>&1; then
310
+ node - "$SETTINGS" ${cmds[@]+"${cmds[@]}"} <<'NODE'
311
+ const fs = require('fs');
312
+ const [,, file, ...cmds] = process.argv;
313
+ let d = {};
314
+ if (fs.existsSync(file) && fs.statSync(file).size > 0) d = JSON.parse(fs.readFileSync(file, 'utf8'));
315
+ d.hooks = d.hooks || {};
316
+ d.hooks.PreToolUse = d.hooks.PreToolUse || [];
317
+ for (const c of cmds) {
318
+ const seen = d.hooks.PreToolUse.some(m => (m.hooks || []).some(h => h.command === c));
319
+ if (!seen) d.hooks.PreToolUse.push({ matcher: 'Bash', hooks: [{ type: 'command', command: c }] });
320
+ }
321
+ fs.writeFileSync(file, JSON.stringify(d, null, 2) + '\n');
322
+ NODE
323
+ elif command -v jq >/dev/null 2>&1; then
324
+ [[ -f "$SETTINGS" ]] || printf '{}\n' > "$SETTINGS"
325
+ local c
326
+ for c in ${cmds[@]+"${cmds[@]}"}; do
327
+ local tmp="$WORK/settings.jq"
328
+ jq --arg c "$c" '
329
+ .hooks //= {} | .hooks.PreToolUse //= [] |
330
+ if ([.hooks.PreToolUse[].hooks[]? | .command] | index($c)) then .
331
+ else .hooks.PreToolUse += [{matcher:"Bash",hooks:[{type:"command",command:$c}]}] end
332
+ ' "$SETTINGS" > "$tmp" && mv "$tmp" "$SETTINGS"
333
+ done
334
+ else
335
+ die "neither node nor jq resolves — cannot merge .claude/settings.json safely (install one, or register the hooks by hand)" 69
336
+ fi
337
+ # NOT recorded in EMITTED_LOG: the backup governs the restore path, and the
338
+ # file itself may be user-owned and pre-existing — never rm'd.
339
+ }
340
+
341
+ unmerge_settings() { # remove the given guards' hook command entries
342
+ local names="$1" c
343
+ [[ -f "$SETTINGS" ]] || return 0
344
+ if command -v node >/dev/null 2>&1; then
345
+ node - "$SETTINGS" $names <<'NODE'
346
+ const fs = require('fs');
347
+ const [,, file, ...names] = process.argv;
348
+ if (!fs.existsSync(file)) process.exit(0);
349
+ const d = JSON.parse(fs.readFileSync(file, 'utf8'));
350
+ if (!d.hooks || !d.hooks.PreToolUse) process.exit(0);
351
+ const drop = new Set(names.map(n => `bash "$CLAUDE_PROJECT_DIR/.claude/hooks/${n}.sh"`));
352
+ d.hooks.PreToolUse = d.hooks.PreToolUse
353
+ .map(m => ({ ...m, hooks: (m.hooks || []).filter(h => !drop.has(h.command)) }))
354
+ .filter(m => (m.hooks || []).length > 0);
355
+ fs.writeFileSync(file, JSON.stringify(d, null, 2) + '\n');
356
+ NODE
357
+ elif command -v jq >/dev/null 2>&1; then
358
+ local tmp="$WORK/settings.jq" expr="."
359
+ for c in $names; do
360
+ expr="$expr | .hooks.PreToolUse = ([.hooks.PreToolUse[]? | .hooks = ([.hooks[]? | select(.command != \"bash \\\"\$CLAUDE_PROJECT_DIR/.claude/hooks/$c.sh\\\"\")])] | map(select((.hooks|length) > 0)))"
361
+ done
362
+ jq "$expr" "$SETTINGS" > "$tmp" && mv "$tmp" "$SETTINGS"
363
+ fi
364
+ }
365
+
366
+ # --- workflow render -----------------------------------------------------------
367
+ # Keep the marker block only for selected ci guards; stamp continue-on-error.
368
+ render_workflow() {
369
+ local tpl="$REF_DIR/guards/verification-gates.yml.template" out="$1"
370
+ local keep_secret=0 keep_orphan=0 g
371
+ for g in $GUARDS; do
372
+ case "$g" in secret-scan) keep_secret=1 ;; orphan-test) keep_orphan=1 ;; esac
373
+ done
374
+ awk -v ks="$keep_secret" -v ko="$keep_orphan" '
375
+ /^ # verification-scaffold:begin:secret-scan$/ { skip = (ks ? 0 : 1); if (skip) next }
376
+ /^ # verification-scaffold:end:secret-scan$/ { if (skip) { skip=0; next } }
377
+ /^ # verification-scaffold:begin:orphan-test$/ { skip = (ko ? 0 : 1); if (skip) next }
378
+ /^ # verification-scaffold:end:orphan-test$/ { if (skip) { skip=0; next } }
379
+ !skip { print }
380
+ ' "$tpl" | sed -e "s|@CI_CONTINUE_ON_ERROR@|$CI_CONTINUE_ON_ERROR|g" > "$out"
381
+ record_emit "$out"
382
+ }
383
+
384
+ # --- default-branch detection (SpecFlow #1) --------------------------------------
385
+ resolve_default_branches() {
386
+ local ref
387
+ ref="$(git -C "$TARGET" symbolic-ref -q --short refs/remotes/origin/HEAD 2>/dev/null || true)"
388
+ if [[ -n "$ref" ]]; then
389
+ # ERE-escape every metachar legal in a ref name — emit_tpl substitutes this
390
+ # string literally into the emitted pattern, so a default named release/1.0
391
+ # or a&b compiles to the intended literal (#10759: a bare & once re-inserted
392
+ # the @DEFAULT_BRANCHES@ placeholder through sed's replacement).
393
+ DEFAULT_BRANCHES="$(printf '%s' "${ref#origin/}" | sed 's/[][\.*^$/|&~()+?{}]/\\&/g')"
394
+ else
395
+ # Raw | — the intended alternation, which is why the escape stays inside
396
+ # the ref-resolved branch only.
397
+ DEFAULT_BRANCHES="main|master"
398
+ fi
399
+ }
400
+
401
+ # --- bite-proof ------------------------------------------------------------------
402
+ WT=""
403
+ BITE_DIR=""
404
+ prove_bite() {
405
+ BITE_DIR="$(mktemp -d -t verification-bite-XXXXXX)"
406
+ WT="$BITE_DIR/wt"
407
+ local git_err
408
+ git_err="$(git -C "$TARGET" worktree add --detach "$WT" HEAD 2>&1 >/dev/null)" \
409
+ || die "git worktree add failed: $(printf '%s' "$git_err" | tail -n 3 | tr '\n' ' ')" 69
410
+ # Mirror the emitted files into the worktree (untracked emits are not in HEAD).
411
+ local f
412
+ while IFS= read -r f; do
413
+ local rel="${f#"$TARGET"/}"
414
+ mkdir -p "$WT/$(dirname "$rel")"
415
+ [[ -f "$f" ]] && cp "$f" "$WT/$rel" && [[ "$f" == *.sh ]] && chmod +x "$WT/$rel"
416
+ done < "$EMITTED_LOG"
417
+
418
+ for g in $GUARDS; do
419
+ case "$g" in
420
+ secret-scan) bite_secret_scan ;;
421
+ commit-on-main) bite_commit_on_main ;;
422
+ block-stash) bite_block_stash ;;
423
+ orphan-test) bite_orphan_test ;;
424
+ esac
425
+ done
426
+ git -C "$TARGET" worktree remove --force "$WT" >/dev/null 2>&1 || true
427
+ rm -rf -- "$BITE_DIR"
428
+ WT=""; BITE_DIR=""
429
+ }
430
+
431
+ bite_fail() { # bite_fail <code> <guard> <msg>
432
+ say "bite-proof FAILED ($1): $2 — $3"
433
+ exit "$1"
434
+ }
435
+
436
+ # Run an emitted hook: stdin payload, cwd = $WT. Captures stdout JSON + stderr.
437
+ # stderr APPENDS to a per-hook log: truncation dropped every earlier arm's
438
+ # diagnostics, while one shared file would let an earlier guard's refusal WARN
439
+ # satisfy a later guard's stderr grep (#10759).
440
+ run_hook() { # run_hook <hook-path> <command> <cwd-override?>
441
+ local hook="$1" cmd="$2" cwd="${3:-$WT}"
442
+ ( cd "$cwd" && printf '%s' "$(payload_json "$cmd" "$cwd")" | bash "$hook" ) \
443
+ 2>>"$BITE_DIR/hook-err.$(basename "$hook" .sh).log"
444
+ }
445
+ payload_json() { # payload_json <command> <cwd>
446
+ if command -v jq >/dev/null 2>&1; then
447
+ jq -nc --arg c "$1" --arg w "$2" '{tool_name:"Bash",tool_input:{command:$c},cwd:$w}'
448
+ elif command -v node >/dev/null 2>&1; then
449
+ node -e 'console.log(JSON.stringify({tool_name:"Bash",tool_input:{command:process.argv[1]},cwd:process.argv[2]}))' "$1" "$2"
450
+ else
451
+ printf '{"tool_name":"Bash","tool_input":{"command":"%s"},"cwd":"%s"}' "$1" "$2"
452
+ fi
453
+ }
454
+ decision_of() { sed -n 's/.*"permissionDecision": *"\([a-z]*\)".*/\1/p' "$1" | head -n 1; }
455
+ expect_decision() { # expect_decision <guard> <stage> <got-file> <want...>
456
+ local g="$1" stage="$2" f="$3"; shift 3
457
+ local got; got="$(decision_of "$f")"
458
+ local w
459
+ for w in "$@"; do [[ "$got" == "$w" ]] && return 0; done
460
+ return 1
461
+ }
462
+
463
+ bite_secret_scan() {
464
+ if ! command -v gitleaks >/dev/null 2>&1; then
465
+ say "bite-proof secret-scan: SKIP — gitleaks is not on PATH (the hook will warn+allow per commit; the CI job still scans). Install gitleaks 8.24.x to prove this arm."
466
+ return 0
467
+ fi
468
+ local hook="$WT/.claude/hooks/secret-scan.sh" out
469
+ # pass: clean staged file
470
+ printf 'hello\n' > "$WT/bite-clean.txt"
471
+ git -C "$WT" add bite-clean.txt
472
+ out="$(run_hook "$hook" "git commit -m x")" || true
473
+ expect_decision secret-scan pass <(printf '%s' "$out") allow \
474
+ || bite_fail 71 secret-scan "clean staged tree did not allow (got: $out; stderr: $(cat "$BITE_DIR/hook-err.secret-scan.log"))"
475
+ # fail: staged secret-shaped string
476
+ # Synthetic-but-shaped secret (the AWS docs example key is allowlisted in
477
+ # gitleaks's default ruleset — this variant keeps the 40-char shape only).
478
+ printf 'AWS_SECRET_ACCESS_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYSYNTHETIC0"\n' > "$WT/bite-secret.txt"
479
+ git -C "$WT" add bite-secret.txt
480
+ out="$(run_hook "$hook" "git commit -m x")" || true
481
+ if [[ "$MODE" == "enforce" ]]; then want=deny; else want=ask; fi
482
+ expect_decision secret-scan fail <(printf '%s' "$out") "$want" \
483
+ || bite_fail 72 secret-scan "staged secret did not produce $want (got: $out; stderr: $(cat "$BITE_DIR/hook-err.secret-scan.log"))"
484
+ # pass again: revert
485
+ git -C "$WT" rm -q --cached bite-secret.txt && rm -f "$WT/bite-secret.txt"
486
+ out="$(run_hook "$hook" "git commit -m x")" || true
487
+ expect_decision secret-scan pass2 <(printf '%s' "$out") allow \
488
+ || bite_fail 73 secret-scan "did not return to green after the probe was reverted (got: $out)"
489
+ say "bite-proof secret-scan: pass -> fail($want) -> pass"
490
+ }
491
+
492
+ bite_commit_on_main() {
493
+ local hook="$WT/.claude/hooks/commit-on-main.sh" out
494
+ local fx="$BITE_DIR/fx-commit" first="${DEFAULT_BRANCHES%%|*}"
495
+ first="${first//\\/}" # un-escape for git branch creation
496
+ mkdir -p "$fx"
497
+ # symbolic-ref points the unborn HEAD at the resolved default BEFORE the first
498
+ # commit — `git init -b` would fail on old gits and `checkout -b` collides when
499
+ # the init default already IS the resolved name.
500
+ git -C "$fx" init -q
501
+ git -C "$fx" symbolic-ref HEAD "refs/heads/$first"
502
+ git -C "$fx" -c user.email=t@t -c user.name=t commit -q --allow-empty -m init
503
+ git -C "$fx" checkout -qb feat-bite
504
+ local want; [[ "$MODE" == "enforce" ]] && want=deny || want=allow
505
+ # The hook resolves its guard via the cwd's toplevel — run it from the
506
+ # worktree; the PAYLOAD's -C targets the fixture repo the guard branches on.
507
+ # pass: feature branch
508
+ out="$(run_hook "$hook" "git -C $fx commit -m x" "$WT")" || true
509
+ expect_decision commit-on-main pass <(printf '%s' "$out") allow \
510
+ || bite_fail 71 commit-on-main "feature-branch payload was not allowed (got: $out; stderr: $(cat "$BITE_DIR/hook-err.commit-on-main.log"))"
511
+ # fail: default branch
512
+ git -C "$fx" checkout -q "$first"
513
+ out="$(run_hook "$hook" "git -C $fx commit -m x" "$WT")" || true
514
+ expect_decision commit-on-main fail <(printf '%s' "$out") "$want" \
515
+ || bite_fail 72 commit-on-main "default-branch ($first) payload did not produce $want (got: $out; stderr: $(cat "$BITE_DIR/hook-err.commit-on-main.log"))"
516
+ # Advisory must warn a REFUSAL on stderr — an allow with no signal is a silent
517
+ # guard, and a tool-error warn must not satisfy the arm either.
518
+ if [[ "$MODE" == "advisory" ]] && ! grep -qE 'not allowed|refused' "$BITE_DIR/hook-err.commit-on-main.log"; then
519
+ bite_fail 72 commit-on-main "advisory refusal carried no refusal WARN on stderr (got: $out; stderr: $(cat "$BITE_DIR/hook-err.commit-on-main.log"))"
520
+ fi
521
+ # pass again
522
+ git -C "$fx" checkout -q feat-bite
523
+ out="$(run_hook "$hook" "git -C $fx commit -m x" "$WT")" || true
524
+ expect_decision commit-on-main pass2 <(printf '%s' "$out") allow \
525
+ || bite_fail 73 commit-on-main "did not return to allow on a feature branch (got: $out)"
526
+ say "bite-proof commit-on-main: pass -> fail($want) -> pass"
527
+ }
528
+
529
+ bite_block_stash() {
530
+ local hook="$WT/.claude/hooks/block-stash.sh" out want
531
+ [[ "$MODE" == "enforce" ]] && want=deny || want=allow
532
+ out="$(run_hook "$hook" "git status")" || true
533
+ expect_decision block-stash pass <(printf '%s' "$out") allow \
534
+ || bite_fail 71 block-stash "git status was not allowed (got: $out)"
535
+ out="$(run_hook "$hook" "git add x && git stash pop")" || true
536
+ expect_decision block-stash fail <(printf '%s' "$out") "$want" \
537
+ || bite_fail 72 block-stash "chained 'git stash pop' did not produce $want (got: $out)"
538
+ if [[ "$MODE" == "advisory" ]] && ! grep -qE 'not allowed' "$BITE_DIR/hook-err.block-stash.log"; then
539
+ bite_fail 72 block-stash "advisory refusal carried no refusal WARN on stderr (got: $out; stderr: $(cat "$BITE_DIR/hook-err.block-stash.log"))"
540
+ fi
541
+ out="$(run_hook "$hook" "git stash list")" || true
542
+ expect_decision block-stash pass2 <(printf '%s' "$out") allow \
543
+ || bite_fail 73 block-stash "documented read-only 'git stash list' was not allowed (got: $out)"
544
+ say "bite-proof block-stash: pass -> fail($want) -> pass"
545
+ }
546
+
547
+ bite_orphan_test() {
548
+ local check="$WT/scripts/verification/orphan-test-check.sh" out rc
549
+ # pass: current tree (grandfather rows already cover pre-existing orphans)
550
+ out="$(cd "$WT" && bash "$check" 2>&1)" || bite_fail 71 orphan-test "clean tree did not pass: $out"
551
+ # fail: an unregistered suite
552
+ printf '#!/usr/bin/env bash\nexit 0\n' > "$WT/scratch-bite.test.sh"
553
+ git -C "$WT" add scratch-bite.test.sh
554
+ rc=0; out="$(cd "$WT" && bash "$check" 2>&1)" || rc=$?
555
+ if [[ "$rc" -eq 0 ]] || ! grep -q 'scratch-bite.test.sh' <<<"$out"; then
556
+ git -C "$WT" rm -q --cached scratch-bite.test.sh; rm -f "$WT/scratch-bite.test.sh"
557
+ bite_fail 72 orphan-test "injected unregistered suite was not named (rc=$rc): $out"
558
+ fi
559
+ # pass again
560
+ git -C "$WT" rm -q --cached scratch-bite.test.sh; rm -f "$WT/scratch-bite.test.sh"
561
+ out="$(cd "$WT" && bash "$check" 2>&1)" \
562
+ || bite_fail 73 orphan-test "did not return to green after the probe was reverted: $out"
563
+ say "bite-proof orphan-test: pass -> fail(named scratch-bite.test.sh) -> pass"
564
+ }
565
+
566
+ # --- doc block (append-once, written LAST) -----------------------------------------
567
+ emit_doc() {
568
+ local guard_list="${GUARDS// /, }" guard_rows="" g surfaces artifacts decides
569
+ for g in $GUARDS; do
570
+ surfaces="$(_guard_field "$g" 3)"
571
+ artifacts="$(printf '%s' "$(_guard_field "$g" 8)" | tr ';' ' ')"
572
+ case "$g" in
573
+ secret-scan) decides="secret-shaped strings staged for commit" ;;
574
+ commit-on-main) decides="commits on the default branch(es): $DEFAULT_BRANCHES" ;;
575
+ block-stash) decides="every git stash except list/show" ;;
576
+ orphan-test) decides="tracked *.test.sh named by no runner surface" ;;
577
+ esac
578
+ guard_rows="$guard_rows| \`$g\` ($surfaces) | \`$artifacts\` | $decides |"$'\n'
579
+ done
580
+ printf '%s' "$guard_rows" > "$WORK/doc-rows"
581
+ local content
582
+ content="$(sed -e "s|@MODE@|$MODE|g" -e "s|@GUARD_LIST@|$guard_list|g" \
583
+ -e "s|@DATE@|$(date -u +%Y-%m-%d)|g" \
584
+ -e "/@GUARD_TABLE@/r $WORK/doc-rows" -e "/@GUARD_TABLE@/d" \
585
+ "$REF_DIR/verification-readme.template")"
586
+ local doc="$TARGET/VERIFICATION.md"
587
+ [[ -e "$doc" || -L "$doc" ]] && doc="$TARGET/README.md"
588
+ [[ -L "$doc" ]] && { warn "refusing to append through a symlink: ${doc#"$TARGET"/}"; return 0; }
589
+ if grep -qF 'verification-scaffold:readme:start' "$doc" 2>/dev/null; then
590
+ log "doc block already present in ${doc#"$TARGET"/}"
591
+ return 0
592
+ fi
593
+ [[ -s "$doc" && -n "$(tail -c 1 "$doc")" ]] && printf '\n' >> "$doc"
594
+ printf '%s\n' "$content" >> "$doc" \
595
+ || warn "could not append the doc block to ${doc#"$TARGET"/} — the guards are installed and proven; add references/verification-readme.template by hand"
596
+ }
597
+
598
+ # --- --uninstall -------------------------------------------------------------------
599
+ if [[ -n "$UNINSTALL" ]]; then
600
+ g="$UNINSTALL"
601
+ emits="$(_guard_field "$g" 8)"
602
+ removed=""
603
+ IFS=';' read -ra paths <<<"$emits"
604
+ for p in "${paths[@]}"; do
605
+ f="$TARGET/$p"
606
+ case "$p" in
607
+ .github/workflows/verification-gates.yml)
608
+ # Shared artifact: strip only this guard's job block; delete only when no
609
+ # other selected-capable ci guard remains installed.
610
+ other_ci=0
611
+ for og in $(v1_guards); do
612
+ [[ "$og" == "$g" ]] && continue
613
+ case "$(_guard_field "$og" 3)" in *ci*)
614
+ IFS=';' read -ra op <<<"$(_guard_field "$og" 8)"
615
+ for q in "${op[@]}"; do [[ "$q" == "scripts/verification/orphan-test-check.sh" || "$q" == ".claude/hooks/secret-scan.sh" ]] && [[ -e "$TARGET/$q" ]] && other_ci=1; done
616
+ esac
617
+ done
618
+ if [[ -f "$f" ]]; then
619
+ if [[ "$other_ci" -eq 0 ]]; then
620
+ rm -f -- "$f"; removed="$removed $p"
621
+ elif grep -qF "# verification-scaffold:begin:$g" "$f"; then
622
+ sed "/# verification-scaffold:begin:$g/,/# verification-scaffold:end:$g/d" "$f" > "$f.tmp" && mv "$f.tmp" "$f"
623
+ removed="$removed $p($g-job-stripped)"
624
+ fi
625
+ # other_ci=1 with no begin:$g marker: this guard's job block was never
626
+ # emitted (subset install) — the shared file stays byte-identical and
627
+ # nothing is reported (#10759 phantom-job-strip).
628
+ fi ;;
629
+ .gitleaks.toml)
630
+ if [[ -f "$f" ]]; then
631
+ if cmp -s "$f" "$REF_DIR/gitleaks.toml.template"; then rm -f -- "$f"; removed="$removed $p"
632
+ else warn "leaving modified $p (no longer the emitted bytes — remove by hand if unwanted)"; fi
633
+ fi ;;
634
+ .claude/hooks/*.sh|scripts/verification/*)
635
+ [[ -e "$f" ]] && { rm -f -- "$f"; removed="$removed $p"; } ;;
636
+ *) [[ -e "$f" ]] && { rm -f -- "$f"; removed="$removed $p"; } ;;
637
+ esac
638
+ done
639
+ # settings.json hook entries for this guard's hooks
640
+ hook_names=""
641
+ for p in "${paths[@]}"; do case "$p" in .claude/hooks/*.sh) hook_names="$hook_names $(basename "$p" .sh)" ;; esac; done
642
+ [[ -n "$hook_names" ]] && unmerge_settings "$hook_names"
643
+ # Empty dirs — only those THIS scaffold created (the persisted ledger), only
644
+ # when empty (rmdir enforces that).
645
+ if [[ -f "$TARGET/.claude/.verification-scaffold-dirs" ]]; then
646
+ while IFS= read -r d; do [[ -d "$d" ]] && rmdir "$d" 2>/dev/null || true; done \
647
+ < <(awk '{a[NR]=$0} END{for(i=NR;i>0;i--)print a[i]}' "$TARGET/.claude/.verification-scaffold-dirs")
648
+ fi
649
+ # Drop the ledger itself when no v1 guard has a single artifact left.
650
+ left=""
651
+ for og in $(v1_guards); do
652
+ IFS=';' read -ra ep <<<"$(_guard_field "$og" 8)"
653
+ for p in "${ep[@]}"; do [[ -e "$TARGET/$p" ]] && left=1; done
654
+ done
655
+ [[ -z "$left" ]] && rm -f -- "$TARGET/.claude/.verification-scaffold-dirs" \
656
+ && rmdir "$TARGET/.claude" 2>/dev/null || true
657
+ # Nothing installed -> the marker doc block is a stale claim that guards are
658
+ # present; strip the begin:end range (only when BOTH markers are present, so a
659
+ # truncated block can never delete to EOF) and drop the file if it emptied
660
+ # (#10759 — VERIFICATION.md is the block alone; README.md keeps its content).
661
+ if [[ -z "$left" ]]; then
662
+ for doc in "$TARGET/VERIFICATION.md" "$TARGET/README.md"; do
663
+ [[ -f "$doc" && ! -L "$doc" ]] || continue
664
+ grep -qF 'verification-scaffold:readme:start' "$doc" || continue
665
+ grep -qF 'verification-scaffold:readme:end' "$doc" || continue
666
+ sed '/verification-scaffold:readme:start/,/verification-scaffold:readme:end/d' "$doc" > "$WORK/docstrip" \
667
+ && mv "$WORK/docstrip" "$doc"
668
+ [[ -s "$doc" ]] || rm -f -- "$doc"
669
+ removed="$removed ${doc#"$TARGET"/}(doc-block)"
670
+ done
671
+ fi
672
+ if [[ -z "$removed" ]]; then
673
+ say "$g: not installed — nothing removed."
674
+ for og in $(v1_guards); do
675
+ inst=""
676
+ IFS=';' read -ra ep <<<"$(_guard_field "$og" 8)"
677
+ for p in "${ep[@]}"; do [[ -e "$TARGET/$p" ]] && inst="$inst $p"; done
678
+ [[ -n "$inst" ]] && say "installed:$og →${inst}"
679
+ done
680
+ exit 0
681
+ fi
682
+ say "uninstalled $g — removed:${removed}"
683
+ exit 0
684
+ fi
685
+
686
+ # --- default mode ------------------------------------------------------------------
687
+ check_tmpdir_outside_repo
688
+ resolve_default_branches
689
+ [[ "$MODE" == "enforce" ]] && CI_CONTINUE_ON_ERROR="false" || CI_CONTINUE_ON_ERROR="true"
690
+
691
+ # Merge tool precheck BEFORE the lock/write window (69 with named remediation).
692
+ need_merge=0
693
+ for g in $GUARDS; do case "$(_guard_field "$g" 3)" in *hook*) need_merge=1 ;; esac; done
694
+ if [[ "$need_merge" -eq 1 ]] && ! command -v node >/dev/null 2>&1 && ! command -v jq >/dev/null 2>&1; then
695
+ die "no node and no jq on PATH — cannot merge .claude/settings.json; install either or deselect the hook guards" 69
696
+ fi
697
+ # Malformed existing settings.json refused pre-write (AC7).
698
+ if [[ -f "$SETTINGS" ]]; then
699
+ if command -v node >/dev/null 2>&1; then
700
+ node -e 'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))' "$SETTINGS" 2>/dev/null \
701
+ || die ".claude/settings.json is not valid JSON — refusing before any write" 69
702
+ elif command -v jq >/dev/null 2>&1; then
703
+ jq -e . "$SETTINGS" >/dev/null 2>&1 || die ".claude/settings.json is not valid JSON — refusing before any write" 69
704
+ fi
705
+ fi
706
+
707
+ # Refuse-if-exists over every emit path (deduped), BEFORE anything is written.
708
+ # .claude/settings.json is merged, never refused. Doc files are append-once.
709
+ collide="" seen=""
710
+ for g in $GUARDS; do
711
+ IFS=';' read -ra ep <<<"$(_guard_field "$g" 8)"
712
+ for p in "${ep[@]}"; do
713
+ [[ "$p" == ".claude/settings.json" ]] && continue
714
+ case " $seen " in *" $p "*) continue ;; esac
715
+ seen="$seen $p"
716
+ [[ -e "$TARGET/$p" ]] && collide="$collide $p"
717
+ done
718
+ done
719
+ [[ -n "$collide" ]] && die "refuse-if-exists:${collide} already present (no --force). Remove or --uninstall the owning guard first." 66
720
+
721
+ if [[ "$DRY_RUN" -eq 1 ]]; then
722
+ say "dry-run — would emit into $TARGET (mode=$MODE, default-branches=$DEFAULT_BRANCHES):"
723
+ for g in $GUARDS; do
724
+ say " [$g]"
725
+ IFS=';' read -ra ep <<<"$(_guard_field "$g" 8)"
726
+ for p in "${ep[@]}"; do say " $p"; done
727
+ done
728
+ if [[ "$need_merge" -eq 1 ]]; then
729
+ say " merge .claude/settings.json (PreToolUse Bash):"
730
+ for g in $GUARDS; do
731
+ IFS=';' read -ra ep <<<"$(_guard_field "$g" 8)"
732
+ for p in "${ep[@]}"; do case "$p" in .claude/hooks/*.sh) say " hook: $p" ;; esac; done
733
+ done
734
+ fi
735
+ say " doc block → VERIFICATION.md (else README.md marker block), written last"
736
+ say " then a TMPDIR detached-worktree bite-proof per guard (pass -> fail -> pass)"
737
+ exit 0
738
+ fi
739
+
740
+ # Arm self-cleanup before the FIRST write.
741
+ CLEANUP_ARMED=1
742
+ trap '_vs_cleanup' EXIT
743
+ trap '_vs_cleanup interrupted; trap - EXIT; exit 143' INT TERM
744
+ take_run_lock
745
+
746
+ # Emission order (Guard 5): hooks+scripts+aux → settings merge → workflow → bite → doc.
747
+ ensure_dir "$TARGET/.claude/hooks"
748
+ ensure_dir "$TARGET/scripts/verification"
749
+ ensure_dir "$TARGET/.github/workflows"
750
+ for g in $GUARDS; do
751
+ emit_guard "$g"
752
+ log "emitted guard: $g"
753
+ done
754
+ [[ "${#HOOK_COMMANDS[@]}" -gt 0 ]] && merge_settings
755
+ need_workflow=0
756
+ for g in $GUARDS; do case "$(_guard_field "$g" 3)" in *ci*) need_workflow=1 ;; esac; done
757
+ if [[ "$need_workflow" -eq 1 ]]; then
758
+ render_workflow "$TARGET/.github/workflows/verification-gates.yml"
759
+ log "emitted: .github/workflows/verification-gates.yml"
760
+ fi
761
+
762
+ # Persist the created-dir ledger so --uninstall can honor "removed only if the
763
+ # run created them AND they're empty" (SpecFlow #3).
764
+ if [[ -s "$DIRS_LOG" ]]; then
765
+ ensure_dir "$TARGET/.claude"
766
+ cp "$DIRS_LOG" "$TARGET/.claude/.verification-scaffold-dirs"
767
+ record_emit "$TARGET/.claude/.verification-scaffold-dirs"
768
+ fi
769
+
770
+ # Bite-proof, then prose. A repo with no commits cannot host a detached worktree
771
+ # — skip loudly rather than pretend (the emitted artifacts still refuse-if-exists).
772
+ if git -C "$TARGET" rev-parse --verify HEAD >/dev/null 2>&1; then
773
+ prove_bite
774
+ else
775
+ say "bite-proof: SKIP — HEAD does not resolve (no commits yet); the installed guards are unproven until the first commit, then re-run with --guards none semantics: verify by hand"
776
+ fi
777
+
778
+ release_run_lock
779
+ CLEANUP_ARMED=0
780
+ trap - EXIT INT TERM
781
+
782
+ emit_doc
783
+ rm -rf -- "$WORK"
784
+ say "done (mode=$MODE). Guards: ${GUARDS}. Promote per VERIFICATION.md after >=1 clean run."
785
+ exit 0