@soleur/opencode 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (812) hide show
  1. package/.claude-plugin/agents.manifest.json +476 -0
  2. package/.claude-plugin/plugin.json +42 -0
  3. package/README.md +44 -2
  4. package/agents/community/.gitkeep +0 -0
  5. package/agents/engineering/cto.md +87 -0
  6. package/agents/engineering/design/ddd-architect.md +95 -0
  7. package/agents/engineering/discovery/agent-finder.md +214 -0
  8. package/agents/engineering/discovery/functional-discovery.md +182 -0
  9. package/agents/engineering/infra/infra-security.md +151 -0
  10. package/agents/engineering/infra/platform-strategist.md +109 -0
  11. package/agents/engineering/infra/terraform-architect.md +171 -0
  12. package/agents/engineering/prompt-engineer.md +37 -0
  13. package/agents/engineering/research/best-practices-researcher.md +115 -0
  14. package/agents/engineering/research/framework-docs-researcher.md +93 -0
  15. package/agents/engineering/research/git-history-analyzer.md +53 -0
  16. package/agents/engineering/research/learnings-researcher.md +285 -0
  17. package/agents/engineering/research/repo-research-analyst.md +118 -0
  18. package/agents/engineering/review/agent-native-reviewer.md +279 -0
  19. package/agents/engineering/review/architecture-strategist.md +61 -0
  20. package/agents/engineering/review/code-quality-analyst.md +92 -0
  21. package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
  22. package/agents/engineering/review/data-integrity-guardian.md +82 -0
  23. package/agents/engineering/review/data-migration-expert.md +98 -0
  24. package/agents/engineering/review/deployment-verification-agent.md +183 -0
  25. package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
  26. package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
  27. package/agents/engineering/review/legacy-code-expert.md +55 -0
  28. package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
  29. package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
  30. package/agents/engineering/review/performance-oracle.md +130 -0
  31. package/agents/engineering/review/security-sentinel.md +167 -0
  32. package/agents/engineering/review/semgrep-sast.md +36 -0
  33. package/agents/engineering/review/test-design-reviewer.md +150 -0
  34. package/agents/engineering/review/user-impact-reviewer.md +70 -0
  35. package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
  36. package/agents/finance/budget-analyst.md +29 -0
  37. package/agents/finance/cfo.md +44 -0
  38. package/agents/finance/financial-reporter.md +30 -0
  39. package/agents/finance/revenue-analyst.md +30 -0
  40. package/agents/legal/clo.md +115 -0
  41. package/agents/legal/legal-compliance-auditor.md +110 -0
  42. package/agents/legal/legal-document-generator.md +134 -0
  43. package/agents/marketing/analytics-analyst.md +25 -0
  44. package/agents/marketing/brand-architect.md +181 -0
  45. package/agents/marketing/cmo.md +76 -0
  46. package/agents/marketing/conversion-optimizer.md +19 -0
  47. package/agents/marketing/copywriter.md +20 -0
  48. package/agents/marketing/fact-checker.md +70 -0
  49. package/agents/marketing/growth-strategist.md +145 -0
  50. package/agents/marketing/paid-media-strategist.md +28 -0
  51. package/agents/marketing/pricing-strategist.md +17 -0
  52. package/agents/marketing/programmatic-seo-specialist.md +25 -0
  53. package/agents/marketing/retention-strategist.md +23 -0
  54. package/agents/marketing/seo-aeo-analyst.md +164 -0
  55. package/agents/operations/coo.md +50 -0
  56. package/agents/operations/ops-advisor.md +78 -0
  57. package/agents/operations/ops-provisioner.md +101 -0
  58. package/agents/operations/ops-research.md +52 -0
  59. package/agents/operations/service-automator.md +278 -0
  60. package/agents/product/business-validator.md +206 -0
  61. package/agents/product/competitive-intelligence.md +89 -0
  62. package/agents/product/cpo.md +63 -0
  63. package/agents/product/design/ux-design-lead.md +209 -0
  64. package/agents/product/spec-flow-analyzer.md +122 -0
  65. package/agents/sales/cro.md +44 -0
  66. package/agents/sales/deal-architect.md +29 -0
  67. package/agents/sales/outbound-strategist.md +29 -0
  68. package/agents/sales/pipeline-analyst.md +29 -0
  69. package/agents/support/cco.md +48 -0
  70. package/agents/support/community-manager.md +570 -0
  71. package/agents/support/ticket-triage.md +70 -0
  72. package/bin/soleur-opencode.js +29 -0
  73. package/commands/go.md +659 -0
  74. package/commands/help.md +273 -0
  75. package/commands/sync.md +977 -0
  76. package/commands/version.md +103 -0
  77. package/hooks/antigravity-hooks.json +84 -0
  78. package/hooks/antigravity-session-start.sh +15 -0
  79. package/hooks/bare-root-cwd-guard.sh +131 -0
  80. package/hooks/browser-snapshot-credential-guard.sh +200 -0
  81. package/hooks/codex-session-start.sh +9 -0
  82. package/hooks/compaction-state.sh +525 -0
  83. package/hooks/destructive-command-guard.sh +1387 -0
  84. package/hooks/devin-session-start.sh +90 -0
  85. package/hooks/ext-filter-detect.sh +171 -0
  86. package/hooks/hooks.json +133 -0
  87. package/hooks/lib/hook-tool-kind.sh +24 -0
  88. package/hooks/lib/log-rotation.sh +176 -0
  89. package/hooks/lib/shell-argv.pl +576 -0
  90. package/hooks/memory-backstop.sh +1114 -0
  91. package/hooks/operator-stage-approval.sh +391 -0
  92. package/hooks/stop-hook.sh +367 -0
  93. package/hooks/unkept-promise-hook.sh +383 -0
  94. package/hooks/version-banner.sh +127 -0
  95. package/hooks/welcome-hook.sh +50 -0
  96. package/install.js +108 -0
  97. package/lib/agent-registry.ts +154 -0
  98. package/lib/c4-canonical-cli.mjs +34 -0
  99. package/lib/c4-canonical.mjs +46 -0
  100. package/lib/c4-from-components.ts +554 -0
  101. package/lib/go-routing.ts +81 -0
  102. package/lib/grok-inspect-contract.ts +311 -0
  103. package/lib/harness-model-map.ts +101 -0
  104. package/lib/harness-parity.ts +726 -0
  105. package/lib/harness-tool-map.ts +180 -0
  106. package/lib/harness.ts +716 -0
  107. package/lib/heartbeat-live-reconcile.ts +1153 -0
  108. package/lib/heartbeat-manifest.ts +342 -0
  109. package/lib/kb-coverage.ts +252 -0
  110. package/lib/pr-merge-poll.ts +103 -0
  111. package/lib/workflow-fidelity.ts +388 -0
  112. package/opencode/INSTRUCTIONS.md +152 -0
  113. package/opencode/agents/engineering/cto.md +10 -0
  114. package/opencode/agents/engineering/design/ddd-architect.md +10 -0
  115. package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
  116. package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
  117. package/opencode/agents/engineering/infra/infra-security.md +10 -0
  118. package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
  119. package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
  120. package/opencode/agents/engineering/prompt-engineer.md +10 -0
  121. package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
  122. package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
  123. package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
  124. package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
  125. package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
  126. package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
  127. package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
  128. package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
  129. package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
  130. package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
  131. package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
  132. package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
  133. package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
  134. package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
  135. package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
  136. package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
  137. package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
  138. package/opencode/agents/engineering/review/performance-oracle.md +10 -0
  139. package/opencode/agents/engineering/review/security-sentinel.md +10 -0
  140. package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
  141. package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
  142. package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
  143. package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
  144. package/opencode/agents/finance/budget-analyst.md +10 -0
  145. package/opencode/agents/finance/cfo.md +10 -0
  146. package/opencode/agents/finance/financial-reporter.md +10 -0
  147. package/opencode/agents/finance/revenue-analyst.md +10 -0
  148. package/opencode/agents/legal/clo.md +10 -0
  149. package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
  150. package/opencode/agents/legal/legal-document-generator.md +10 -0
  151. package/opencode/agents/marketing/analytics-analyst.md +10 -0
  152. package/opencode/agents/marketing/brand-architect.md +10 -0
  153. package/opencode/agents/marketing/cmo.md +10 -0
  154. package/opencode/agents/marketing/conversion-optimizer.md +10 -0
  155. package/opencode/agents/marketing/copywriter.md +10 -0
  156. package/opencode/agents/marketing/fact-checker.md +10 -0
  157. package/opencode/agents/marketing/growth-strategist.md +10 -0
  158. package/opencode/agents/marketing/paid-media-strategist.md +10 -0
  159. package/opencode/agents/marketing/pricing-strategist.md +10 -0
  160. package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
  161. package/opencode/agents/marketing/retention-strategist.md +10 -0
  162. package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
  163. package/opencode/agents/operations/coo.md +10 -0
  164. package/opencode/agents/operations/ops-advisor.md +10 -0
  165. package/opencode/agents/operations/ops-provisioner.md +10 -0
  166. package/opencode/agents/operations/ops-research.md +10 -0
  167. package/opencode/agents/operations/service-automator.md +10 -0
  168. package/opencode/agents/product/business-validator.md +10 -0
  169. package/opencode/agents/product/competitive-intelligence.md +10 -0
  170. package/opencode/agents/product/cpo.md +10 -0
  171. package/opencode/agents/product/design/ux-design-lead.md +10 -0
  172. package/opencode/agents/product/spec-flow-analyzer.md +10 -0
  173. package/opencode/agents/sales/cro.md +10 -0
  174. package/opencode/agents/sales/deal-architect.md +10 -0
  175. package/opencode/agents/sales/outbound-strategist.md +10 -0
  176. package/opencode/agents/sales/pipeline-analyst.md +10 -0
  177. package/opencode/agents/support/cco.md +10 -0
  178. package/opencode/agents/support/community-manager.md +10 -0
  179. package/opencode/agents/support/ticket-triage.md +10 -0
  180. package/opencode/commands/go.md +10 -0
  181. package/opencode/commands/help.md +10 -0
  182. package/opencode/commands/sync.md +10 -0
  183. package/opencode/commands/version.md +11 -0
  184. package/opencode/opencode.json +8 -0
  185. package/opencode/plugin.ts +493 -0
  186. package/package.json +36 -4
  187. package/scripts/admin-merge-ready.sh +545 -0
  188. package/scripts/admin-merge-ready.test.sh +753 -0
  189. package/scripts/affected-tests.sh +908 -0
  190. package/scripts/affected-tests.test.sh +1797 -0
  191. package/scripts/alpha-metrics.sh +78 -0
  192. package/scripts/alpha-metrics.test.sh +115 -0
  193. package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
  194. package/scripts/audit-flag-flip.sh +107 -0
  195. package/scripts/check-red-on-main.sh +316 -0
  196. package/scripts/ci-head-verdict.sh +363 -0
  197. package/scripts/cloud-detect.sh +193 -0
  198. package/scripts/delegation-verify.sh +657 -0
  199. package/scripts/delegation-verify.test.sh +1424 -0
  200. package/scripts/deploy-arm.sh +475 -0
  201. package/scripts/domain-model-drift.sh +419 -0
  202. package/scripts/emit-decision.sh +144 -0
  203. package/scripts/emit-decision.test.sh +144 -0
  204. package/scripts/ext-filter-divergence-corpus.txt +15 -0
  205. package/scripts/ext-filter-divergence.sh +189 -0
  206. package/scripts/generate-c4-from-components.ts +442 -0
  207. package/scripts/grok-fidelity-gate.sh +68 -0
  208. package/scripts/grok-pre-push-gate.sh +232 -0
  209. package/scripts/harness-discovery-smoke.ts +906 -0
  210. package/scripts/harness-parity-census.ts +92 -0
  211. package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
  212. package/scripts/install-opencode-adapter.ts +520 -0
  213. package/scripts/lib/affected-tests/common.sh +365 -0
  214. package/scripts/lib/affected-tests/go.sh +157 -0
  215. package/scripts/lib/affected-tests/js.sh +188 -0
  216. package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
  217. package/scripts/lib/affected-tests/python.sh +185 -0
  218. package/scripts/lib/context-sanitize.sh +49 -0
  219. package/scripts/lib/domain-model-lib.sh +180 -0
  220. package/scripts/lib/ext-filter-grammar.tsv +34 -0
  221. package/scripts/lib/operator-script.sh +1236 -0
  222. package/scripts/lib/proc.sh +580 -0
  223. package/scripts/lib/session-state.sh +748 -0
  224. package/scripts/lib/tmp-classify.sh +843 -0
  225. package/scripts/lib/wrapper-boundary.sh +47 -0
  226. package/scripts/lint-ratchet.py +1547 -0
  227. package/scripts/monitor-pr-checks.sh +441 -0
  228. package/scripts/pipeline-tally.sh +756 -0
  229. package/scripts/pipeline-tally.test.sh +740 -0
  230. package/scripts/plugin-version.sh +528 -0
  231. package/scripts/precommit-guard.sh +113 -0
  232. package/scripts/precommit-guard.test.sh +254 -0
  233. package/scripts/reconcile-live-heartbeats.ts +705 -0
  234. package/scripts/render-c4-model.sh +217 -0
  235. package/scripts/resolve-git-root.sh +55 -0
  236. package/scripts/resolve-regenerable-conflicts.sh +363 -0
  237. package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
  238. package/scripts/ruff-requirements.txt +22 -0
  239. package/scripts/run-in-pid-namespace.sh +98 -0
  240. package/scripts/run-in-pid-namespace.test.sh +290 -0
  241. package/scripts/scan-ancestor-signal-helpers.py +556 -0
  242. package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
  243. package/scripts/setup-ralph-loop.sh +238 -0
  244. package/scripts/sync-cursor-name-map.ts +316 -0
  245. package/scripts/sync-grok-agent-compat.ts +188 -0
  246. package/scripts/sync-npm-package.ts +178 -0
  247. package/scripts/sync-opencode-adapter.ts +479 -0
  248. package/scripts/sync-pr-behind.sh +534 -0
  249. package/scripts/sync-pr-behind.test.sh +252 -0
  250. package/scripts/taste-profile-update.sh +180 -0
  251. package/scripts/taste-profile-update.test.sh +167 -0
  252. package/scripts/write-budget-marker.sh +23 -0
  253. package/scripts/write-kb-coverage.ts +113 -0
  254. package/skills/admin-ip-refresh/SKILL.md +81 -0
  255. package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
  256. package/skills/agent-browser/SKILL.md +698 -0
  257. package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
  258. package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
  259. package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
  260. package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
  261. package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
  262. package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
  263. package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
  264. package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
  265. package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
  266. package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
  267. package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
  268. package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
  269. package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
  270. package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
  271. package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
  272. package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
  273. package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
  274. package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
  275. package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
  276. package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
  277. package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
  278. package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
  279. package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
  280. package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
  281. package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
  282. package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
  283. package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
  284. package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
  285. package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
  286. package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
  287. package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
  288. package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
  289. package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
  290. package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
  291. package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
  292. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
  293. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
  294. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
  295. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
  296. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
  297. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
  298. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
  299. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
  300. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
  301. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
  302. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
  303. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
  304. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
  305. package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
  306. package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
  307. package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
  308. package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
  309. package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
  310. package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
  311. package/skills/agent-native-architecture/SKILL.md +479 -0
  312. package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
  313. package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
  314. package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
  315. package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
  316. package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
  317. package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
  318. package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
  319. package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
  320. package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
  321. package/skills/agent-native-architecture/references/product-implications.md +478 -0
  322. package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
  323. package/skills/agent-native-architecture/references/self-modification.md +294 -0
  324. package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
  325. package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
  326. package/skills/agent-native-audit/SKILL.md +300 -0
  327. package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
  328. package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
  329. package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
  330. package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
  331. package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
  332. package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
  333. package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
  334. package/skills/architecture/SKILL.md +436 -0
  335. package/skills/architecture/references/adr-template.md +154 -0
  336. package/skills/architecture/references/likec4-reference.md +136 -0
  337. package/skills/architecture/references/nfr-reference.md +126 -0
  338. package/skills/archive-kb/SKILL.md +86 -0
  339. package/skills/archive-kb/scripts/archive-kb.sh +300 -0
  340. package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
  341. package/skills/atdd-developer/SKILL.md +65 -0
  342. package/skills/brainstorm/SKILL.md +701 -0
  343. package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
  344. package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
  345. package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
  346. package/skills/brainstorm/references/ui-surface-terms.md +42 -0
  347. package/skills/brainstorm-techniques/SKILL.md +231 -0
  348. package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
  349. package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
  350. package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
  351. package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
  352. package/skills/campaign-calendar/SKILL.md +145 -0
  353. package/skills/cf-token-scope/SKILL.md +164 -0
  354. package/skills/cf-token-scope/references/widen-playbook.md +114 -0
  355. package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
  356. package/skills/changelog/SKILL.md +142 -0
  357. package/skills/code-to-prd/SKILL.md +66 -0
  358. package/skills/code-to-prd/references/banner-template.md +12 -0
  359. package/skills/code-to-prd/references/prd-template.md +41 -0
  360. package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
  361. package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
  362. package/skills/code-to-prd/test/fixture/.env.example +7 -0
  363. package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
  364. package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
  365. package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
  366. package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
  367. package/skills/code-to-prd/test/fixture/package.json +6 -0
  368. package/skills/cohort-status/SKILL.md +62 -0
  369. package/skills/community/SKILL.md +210 -0
  370. package/skills/community/scripts/bsky-community.sh +644 -0
  371. package/skills/community/scripts/bsky-setup.sh +631 -0
  372. package/skills/community/scripts/community-router.sh +93 -0
  373. package/skills/community/scripts/discord-community.sh +487 -0
  374. package/skills/community/scripts/discord-setup.sh +784 -0
  375. package/skills/community/scripts/github-community.sh +706 -0
  376. package/skills/community/scripts/hn-community.sh +233 -0
  377. package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
  378. package/skills/community/scripts/linkedin-community.sh +750 -0
  379. package/skills/community/scripts/linkedin-setup.sh +758 -0
  380. package/skills/community/scripts/x-community.sh +890 -0
  381. package/skills/community/scripts/x-setup.sh +713 -0
  382. package/skills/community/test/community-argv.test.sh +2922 -0
  383. package/skills/community/test/github-community.test.sh +981 -0
  384. package/skills/competitive-analysis/SKILL.md +69 -0
  385. package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
  386. package/skills/compound/SKILL.md +673 -0
  387. package/skills/compound/scripts/token-efficiency-report.sh +334 -0
  388. package/skills/compound/test/phase-16.test.sh +379 -0
  389. package/skills/compound-capture/SKILL.md +791 -0
  390. package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
  391. package/skills/compound-capture/assets/resolution-template.md +116 -0
  392. package/skills/compound-capture/references/yaml-schema.md +67 -0
  393. package/skills/compound-capture/schema.yaml +181 -0
  394. package/skills/constraint-scaffold/SKILL.md +175 -0
  395. package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
  396. package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
  397. package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
  398. package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
  399. package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
  400. package/skills/constraint-scaffold/references/shared-runner.template +135 -0
  401. package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
  402. package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
  403. package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
  404. package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
  405. package/skills/constraint-scaffold/test/generator.test.sh +93 -0
  406. package/skills/constraint-scaffold/test/parity.test.sh +285 -0
  407. package/skills/content-writer/SKILL.md +242 -0
  408. package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
  409. package/skills/cron-delete/SKILL.md +56 -0
  410. package/skills/cron-list/SKILL.md +54 -0
  411. package/skills/deepen-plan/SKILL.md +937 -0
  412. package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
  413. package/skills/deploy/SKILL.md +115 -0
  414. package/skills/deploy/references/hetzner-setup.md +65 -0
  415. package/skills/deploy/scripts/deploy.sh +37 -0
  416. package/skills/deploy-docs/SKILL.md +95 -0
  417. package/skills/dhh-rails-style/SKILL.md +203 -0
  418. package/skills/dhh-rails-style/references/architecture.md +717 -0
  419. package/skills/dhh-rails-style/references/controllers.md +323 -0
  420. package/skills/dhh-rails-style/references/frontend.md +556 -0
  421. package/skills/dhh-rails-style/references/gems.md +316 -0
  422. package/skills/dhh-rails-style/references/models.md +388 -0
  423. package/skills/dhh-rails-style/references/testing.md +354 -0
  424. package/skills/discord-content/SKILL.md +126 -0
  425. package/skills/docs-site/SKILL.md +214 -0
  426. package/skills/drain-labeled-backlog/SKILL.md +203 -0
  427. package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
  428. package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
  429. package/skills/drain-prs/SKILL.md +142 -0
  430. package/skills/drain-prs/scripts/triage-prs.sh +192 -0
  431. package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
  432. package/skills/dspy-ruby/SKILL.md +634 -0
  433. package/skills/dspy-ruby/assets/config-template.rb +359 -0
  434. package/skills/dspy-ruby/assets/module-template.rb +326 -0
  435. package/skills/dspy-ruby/assets/signature-template.rb +143 -0
  436. package/skills/dspy-ruby/references/core-concepts.md +268 -0
  437. package/skills/dspy-ruby/references/optimization.md +623 -0
  438. package/skills/dspy-ruby/references/providers.md +335 -0
  439. package/skills/eval-harness/README.md +194 -0
  440. package/skills/eval-harness/SKILL.md +157 -0
  441. package/skills/eval-harness/enums/go-routes.json +13 -0
  442. package/skills/eval-harness/enums/incident-threshold.json +5 -0
  443. package/skills/eval-harness/enums/lane.json +5 -0
  444. package/skills/eval-harness/enums/tool-selection.json +20 -0
  445. package/skills/eval-harness/enums/triage-levels.json +5 -0
  446. package/skills/eval-harness/gated-skills.json +34 -0
  447. package/skills/eval-harness/models.generated.json +5 -0
  448. package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
  449. package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
  450. package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
  451. package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
  452. package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
  453. package/skills/eval-harness/prompts/go-baseline.txt +6 -0
  454. package/skills/eval-harness/prompts/go-skill.txt +21 -0
  455. package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
  456. package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
  457. package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
  458. package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
  459. package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
  460. package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
  461. package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
  462. package/skills/eval-harness/prompts/triage-skill.txt +10 -0
  463. package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
  464. package/skills/eval-harness/scripts/extract-block.cjs +87 -0
  465. package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
  466. package/skills/eval-harness/scripts/gen-models.sh +41 -0
  467. package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
  468. package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
  469. package/skills/eval-harness/scripts/parse-label.cjs +93 -0
  470. package/skills/eval-harness/scripts/verdict.cjs +132 -0
  471. package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
  472. package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
  473. package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
  474. package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
  475. package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
  476. package/skills/eval-harness/test/eval-gate.test.sh +132 -0
  477. package/skills/eval-harness/test/extract-block.test.sh +87 -0
  478. package/skills/eval-harness/test/gate-classification.test.sh +77 -0
  479. package/skills/eval-harness/test/gen-models.test.sh +75 -0
  480. package/skills/eval-harness/test/measure-classification.test.sh +74 -0
  481. package/skills/eval-harness/test/parse-label.test.sh +129 -0
  482. package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
  483. package/skills/eval-harness/test/verdict.test.sh +123 -0
  484. package/skills/every-style-editor/SKILL.md +142 -0
  485. package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
  486. package/skills/feature-tweet/SKILL.md +199 -0
  487. package/skills/feature-video/SKILL.md +412 -0
  488. package/skills/feature-video/scripts/check_deps.sh +281 -0
  489. package/skills/file-todos/SKILL.md +267 -0
  490. package/skills/file-todos/assets/todo-template.md +166 -0
  491. package/skills/fix-issue/SKILL.md +278 -0
  492. package/skills/fix-issue/references/agent-authored-exclusion.md +118 -0
  493. package/skills/fix-issue/references/exclude-label-jq-snippet.md +96 -0
  494. package/skills/flag-bootstrap/SETUP.md +142 -0
  495. package/skills/flag-create/SKILL.md +145 -0
  496. package/skills/flag-create/scripts/create.sh +273 -0
  497. package/skills/flag-delete/SKILL.md +167 -0
  498. package/skills/flag-delete/scripts/delete.sh +288 -0
  499. package/skills/flag-list/SKILL.md +99 -0
  500. package/skills/flag-list/scripts/list.sh +275 -0
  501. package/skills/flag-set-role/SKILL.md +229 -0
  502. package/skills/flag-set-role/scripts/flip.sh +774 -0
  503. package/skills/frontend-anti-slop/SKILL.md +106 -0
  504. package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
  505. package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
  506. package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
  507. package/skills/frontend-design/SKILL.md +77 -0
  508. package/skills/gdpr-gate/NOTICE +136 -0
  509. package/skills/gdpr-gate/SKILL.md +341 -0
  510. package/skills/gdpr-gate/references/fields.md +160 -0
  511. package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
  512. package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
  513. package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
  514. package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
  515. package/skills/gdpr-gate/references/layers/frontend.md +249 -0
  516. package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
  517. package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
  518. package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
  519. package/skills/gdpr-gate/references/legal-consent.md +140 -0
  520. package/skills/gdpr-gate/references/non-negotiables.md +60 -0
  521. package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
  522. package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
  523. package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
  524. package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
  525. package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
  526. package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
  527. package/skills/gemini-imagegen/SKILL.md +283 -0
  528. package/skills/gemini-imagegen/requirements.txt +5 -0
  529. package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
  530. package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
  531. package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
  532. package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
  533. package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
  534. package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
  535. package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
  536. package/skills/git-worktree/SKILL.md +534 -0
  537. package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
  538. package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
  539. package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
  540. package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
  541. package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
  542. package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
  543. package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
  544. package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
  545. package/skills/go/SKILL.md +54 -0
  546. package/skills/growth/SKILL.md +164 -0
  547. package/skills/harvest-debt/SKILL.md +78 -0
  548. package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
  549. package/skills/heal-skill/SKILL.md +173 -0
  550. package/skills/help/SKILL.md +46 -0
  551. package/skills/incident/NOTICE +39 -0
  552. package/skills/incident/SKILL.md +395 -0
  553. package/skills/incident/scripts/dry-run.sh +448 -0
  554. package/skills/incident/scripts/redact-engine.py +412 -0
  555. package/skills/incident/scripts/redact-sentinel.sh +44 -0
  556. package/skills/incident/templates/pir.md +139 -0
  557. package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
  558. package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
  559. package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
  560. package/skills/incident/test/fixtures/positive-corpus.md +87 -0
  561. package/skills/incident/test/redact-sentinel.test.sh +1420 -0
  562. package/skills/invoice/SKILL.md +206 -0
  563. package/skills/kb-glossary/SKILL.md +71 -0
  564. package/skills/kb-glossary/references/glossary-format.md +111 -0
  565. package/skills/kb-glossary/references/rejected-request-register.md +115 -0
  566. package/skills/kb-search/SKILL.md +276 -0
  567. package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
  568. package/skills/legal-audit/SKILL.md +161 -0
  569. package/skills/legal-generate/NOTICE +242 -0
  570. package/skills/legal-generate/SKILL.md +244 -0
  571. package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
  572. package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
  573. package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
  574. package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
  575. package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
  576. package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
  577. package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
  578. package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
  579. package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
  580. package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
  581. package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
  582. package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
  583. package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
  584. package/skills/linear-fetch/SKILL.md +247 -0
  585. package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
  586. package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
  587. package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
  588. package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
  589. package/skills/linear-fetch/test/parity.test.sh +112 -0
  590. package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
  591. package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
  592. package/skills/merge-pr/SKILL.md +668 -0
  593. package/skills/model-launch-review/SKILL.md +255 -0
  594. package/skills/model-launch-review/scripts/audit-models.sh +501 -0
  595. package/skills/one-shot/SKILL.md +316 -0
  596. package/skills/one-shot/references/token-discipline.md +74 -0
  597. package/skills/operator-bootstrap/SKILL.md +412 -0
  598. package/skills/operator-bootstrap/template.sh +439 -0
  599. package/skills/operator-digest/SKILL.md +287 -0
  600. package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
  601. package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
  602. package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
  603. package/skills/operator-rephrase/SKILL.md +98 -0
  604. package/skills/pencil-setup/SKILL.md +201 -0
  605. package/skills/pencil-setup/scripts/check_deps.sh +556 -0
  606. package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
  607. package/skills/pencil-setup/scripts/package-lock.json +1172 -0
  608. package/skills/pencil-setup/scripts/package.json +14 -0
  609. package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
  610. package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
  611. package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
  612. package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
  613. package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
  614. package/skills/plan/SKILL.md +1140 -0
  615. package/skills/plan/references/differential-migration-testing.md +185 -0
  616. package/skills/plan/references/plan-community-discovery.md +42 -0
  617. package/skills/plan/references/plan-founder-check.md +137 -0
  618. package/skills/plan/references/plan-functional-overlap.md +25 -0
  619. package/skills/plan/references/plan-host-fanout.md +51 -0
  620. package/skills/plan/references/plan-issue-templates.md +779 -0
  621. package/skills/plan/references/plan-network-outage-checklist.md +131 -0
  622. package/skills/plan/references/plan-scope-check.md +126 -0
  623. package/skills/plan/references/plan-sharp-edges.md +325 -0
  624. package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
  625. package/skills/plan/references/webapp-cwv-observability.md +143 -0
  626. package/skills/plan-review/SKILL.md +91 -0
  627. package/skills/plan-review/lib/named-panel.mjs +58 -0
  628. package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
  629. package/skills/postmerge/SKILL.md +642 -0
  630. package/skills/postmerge/references/deploy-status-debugging.md +138 -0
  631. package/skills/postmerge/references/graceful-degradation.md +20 -0
  632. package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
  633. package/skills/preflight/SKILL.md +1553 -0
  634. package/skills/preflight/references/check-13-founder-check.md +286 -0
  635. package/skills/preflight/scripts/founder-check.py +1640 -0
  636. package/skills/preflight/scripts/parse-form-a.awk +107 -0
  637. package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
  638. package/skills/product-roadmap/SKILL.md +357 -0
  639. package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
  640. package/skills/provision-cloudflare/SKILL.md +67 -0
  641. package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
  642. package/skills/provision-doppler/SKILL.md +58 -0
  643. package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
  644. package/skills/provision-github/SKILL.md +59 -0
  645. package/skills/provision-github/scripts/provision-github.sh +300 -0
  646. package/skills/provision-hetzner/SKILL.md +76 -0
  647. package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
  648. package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
  649. package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
  650. package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
  651. package/skills/qa/SKILL.md +263 -0
  652. package/skills/qa/references/browser-preflight.md +22 -0
  653. package/skills/questionnaire-generate/SKILL.md +328 -0
  654. package/skills/questionnaire-generate/references/questionnaire.template +60 -0
  655. package/skills/rclone/SKILL.md +162 -0
  656. package/skills/rclone/scripts/check_setup.sh +63 -0
  657. package/skills/release-announce/SKILL.md +65 -0
  658. package/skills/release-docs/SKILL.md +92 -0
  659. package/skills/reproduce-bug/SKILL.md +358 -0
  660. package/skills/resolve-debt/SKILL.md +85 -0
  661. package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
  662. package/skills/resolve-parallel/SKILL.md +45 -0
  663. package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
  664. package/skills/resolve-pr-parallel/SKILL.md +68 -0
  665. package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
  666. package/skills/resolve-todo-parallel/SKILL.md +57 -0
  667. package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
  668. package/skills/review/SKILL.md +1621 -0
  669. package/skills/review/references/anti-slop-scanner-hook.md +40 -0
  670. package/skills/review/references/defect-classes-migrations.md +9 -0
  671. package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
  672. package/skills/review/references/review-e2e-testing.md +116 -0
  673. package/skills/review/references/review-todo-structure.md +165 -0
  674. package/skills/review/references/risk-tier-and-fix-rounds.md +95 -0
  675. package/skills/review/references/semgrep-custom-rules.yaml +174 -0
  676. package/skills/review/references/ultrathink-phases.md +98 -0
  677. package/skills/review/references/wfs.md +6 -0
  678. package/skills/review/scripts/emit-review-trailer.sh +499 -0
  679. package/skills/review/scripts/ensure-semgrep.sh +99 -0
  680. package/skills/review/scripts/fix-round-seats.sh +197 -0
  681. package/skills/review/test/emit-review-trailer.test.sh +387 -0
  682. package/skills/review/test/ensure-semgrep.test.sh +111 -0
  683. package/skills/review/test/fix-round-seats.test.sh +237 -0
  684. package/skills/review/workflows/README.md +147 -0
  685. package/skills/review/workflows/review.workflow.js +667 -0
  686. package/skills/schedule/SKILL.md +796 -0
  687. package/skills/seo-aeo/SKILL.md +139 -0
  688. package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
  689. package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
  690. package/skills/ship/SKILL.md +3022 -0
  691. package/skills/ship/references/adr-ordinal-collision.md +47 -0
  692. package/skills/ship/references/affected-gate-contract.md +115 -0
  693. package/skills/ship/references/ci-run-diagnosis.md +29 -0
  694. package/skills/ship/references/ci-workflow-authoring.md +68 -0
  695. package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
  696. package/skills/ship/references/cto-ruling-armed-push.md +5 -0
  697. package/skills/ship/references/decision-challenges-render.md +71 -0
  698. package/skills/ship/references/detached-battery-verdict.md +13 -0
  699. package/skills/ship/references/feature-tweet-draft.md +42 -0
  700. package/skills/ship/references/followthrough-issue-body-template.md +47 -0
  701. package/skills/ship/references/followthrough-stub-template.sh +92 -0
  702. package/skills/ship/references/merge-queue-dequeue.md +39 -0
  703. package/skills/ship/references/operator-holds.md +149 -0
  704. package/skills/ship/references/pipeline-tally-render.md +43 -0
  705. package/skills/ship/references/pr-overlap.md +153 -0
  706. package/skills/ship/references/queue-mode.md +7 -0
  707. package/skills/ship/references/ready-run-wait.md +36 -0
  708. package/skills/ship/references/red-on-main-quarantine.md +110 -0
  709. package/skills/ship/references/register-update-pr-pattern.md +88 -0
  710. package/skills/ship/references/settle-then-admin-merge.md +130 -0
  711. package/skills/ship/references/supabase-column-probe.md +13 -0
  712. package/skills/ship/scripts/auto-close-scan.sh +76 -0
  713. package/skills/ship/scripts/battery-owed.sh +403 -0
  714. package/skills/ship/scripts/hold-gate-eval.sh +410 -0
  715. package/skills/ship/scripts/net-issue-flow.sh +665 -0
  716. package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
  717. package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
  718. package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
  719. package/skills/skill-creator/SKILL.md +299 -0
  720. package/skills/skill-creator/references/api-security.md +248 -0
  721. package/skills/skill-creator/references/authoring-levers.md +110 -0
  722. package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
  723. package/skills/skill-creator/references/best-practices.md +431 -0
  724. package/skills/skill-creator/references/common-patterns.md +639 -0
  725. package/skills/skill-creator/references/core-principles.md +193 -0
  726. package/skills/skill-creator/references/executable-code.md +188 -0
  727. package/skills/skill-creator/references/iteration-and-testing.md +509 -0
  728. package/skills/skill-creator/references/official-spec.md +193 -0
  729. package/skills/skill-creator/references/recommended-structure.md +180 -0
  730. package/skills/skill-creator/references/skill-structure.md +396 -0
  731. package/skills/skill-creator/references/using-scripts.md +122 -0
  732. package/skills/skill-creator/references/using-templates.md +120 -0
  733. package/skills/skill-creator/references/workflows-and-validation.md +541 -0
  734. package/skills/skill-creator/scripts/init_skill.py +322 -0
  735. package/skills/skill-creator/scripts/package_skill.py +110 -0
  736. package/skills/skill-creator/scripts/quick_validate.py +64 -0
  737. package/skills/skill-creator/templates/router-skill.md +73 -0
  738. package/skills/skill-creator/templates/simple-skill.md +34 -0
  739. package/skills/skill-creator/workflows/add-reference.md +96 -0
  740. package/skills/skill-creator/workflows/add-script.md +104 -0
  741. package/skills/skill-creator/workflows/add-template.md +83 -0
  742. package/skills/skill-creator/workflows/add-workflow.md +128 -0
  743. package/skills/skill-creator/workflows/audit-skill.md +159 -0
  744. package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
  745. package/skills/skill-creator/workflows/create-new-skill.md +207 -0
  746. package/skills/skill-creator/workflows/get-guidance.md +134 -0
  747. package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
  748. package/skills/skill-creator/workflows/verify-skill.md +226 -0
  749. package/skills/skill-security-scan/SKILL.md +145 -0
  750. package/skills/skill-security-scan/references/disclaimer.md +21 -0
  751. package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
  752. package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
  753. package/skills/skill-security-scan/references/override-mechanism.md +171 -0
  754. package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
  755. package/skills/skill-security-scan/references/regex-patterns.md +136 -0
  756. package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
  757. package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
  758. package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
  759. package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
  760. package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
  761. package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
  762. package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
  763. package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
  764. package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
  765. package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
  766. package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
  767. package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
  768. package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
  769. package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
  770. package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
  771. package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
  772. package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
  773. package/skills/skill-security-scan/scripts/lib.sh +197 -0
  774. package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
  775. package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
  776. package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
  777. package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
  778. package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
  779. package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
  780. package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
  781. package/skills/social-distribute/SKILL.md +485 -0
  782. package/skills/spec-templates/SKILL.md +274 -0
  783. package/skills/sync/SKILL.md +49 -0
  784. package/skills/test-browser/SKILL.md +464 -0
  785. package/skills/test-browser/references/feature-map.md +161 -0
  786. package/skills/test-fix-loop/SKILL.md +159 -0
  787. package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
  788. package/skills/triage/SKILL.md +402 -0
  789. package/skills/trigger-cron/SKILL.md +136 -0
  790. package/skills/trigger-cron/scripts/trigger.sh +198 -0
  791. package/skills/user-set-role/SKILL.md +147 -0
  792. package/skills/user-set-role/scripts/set-role.sh +218 -0
  793. package/skills/user-story-writer/SKILL.md +77 -0
  794. package/skills/ux-audit/SKILL.md +251 -0
  795. package/skills/ux-audit/references/finding.schema.json +62 -0
  796. package/skills/ux-audit/references/route-list.yaml +95 -0
  797. package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
  798. package/skills/ux-audit/scripts/bot-signin.ts +135 -0
  799. package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
  800. package/skills/work/SKILL.md +1479 -0
  801. package/skills/work/references/end-of-work-resume.md +7 -0
  802. package/skills/work/references/hook-test-main-cwd.md +24 -0
  803. package/skills/work/references/key-principles.md +83 -0
  804. package/skills/work/references/property-testing.md +122 -0
  805. package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
  806. package/skills/work/references/work-agent-teams.md +97 -0
  807. package/skills/work/references/work-lifecycle-parallel.md +147 -0
  808. package/skills/work/references/work-lockfile-bumps.md +97 -0
  809. package/skills/work/references/work-scratch-sandboxes.md +212 -0
  810. package/skills/work/references/work-subagent-fanout.md +61 -0
  811. package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
  812. package/skills/xcode-test/SKILL.md +360 -0
@@ -0,0 +1,252 @@
1
+ #!/usr/bin/env bash
2
+ # Suite for plugins/soleur/scripts/sync-pr-behind.sh -- specifically its regenerable-conflict
3
+ # arm (#8377, ADR-235).
4
+ #
5
+ # ── SCOPE, STATED HONESTLY ──────────────────────────────────────────────────────────────────
6
+ # This covers the branch the resolver added and the two outcomes the caller must distinguish:
7
+ # resolver rc 0 -> the merge is already committed; DO NOT merge again; push; succeed.
8
+ # resolver non-zero -> today's behaviour, unchanged: exit 6 with a clean tree.
9
+ # It does NOT cover the gh-polling loop, the BEHIND cap, or exit 7 -- those predate this change
10
+ # and have no suite; adding one is not this PR's subject. Saying so beats implying otherwise by
11
+ # a suite name that suggests whole-script coverage.
12
+ #
13
+ # ── HOW THE SEAM IS BUILT ───────────────────────────────────────────────────────────────────
14
+ # `gh` is a PATH stub that reports OPEN DIRTY once, then OPEN CLEAN. The stub REFUSES a request
15
+ # it did not expect (exit 64) rather than answering every question identically -- a fake that
16
+ # answers regardless of argv puts the seam above everything the caller's request shape encodes,
17
+ # so a caller querying the wrong thing would still read the right fixture.
18
+ export TMPDIR="${TMPDIR:-/var/tmp}"
19
+
20
+ set -uo pipefail
21
+
22
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ SUT="$SCRIPT_DIR/sync-pr-behind.sh"
24
+
25
+ passes=0; fails=0; CASES_RUN=0; FAILED=()
26
+ pass() { passes=$((passes + 1)); echo " PASS: $1"; }
27
+ fail() { fails=$((fails + 1)); FAILED+=("$1"); echo " FAIL: $1" >&2; }
28
+
29
+ _iv_p="$passes"; _iv_f="$fails"; _iv_n="${#FAILED[@]}"
30
+ { pass "self-test"; fail "self-test"; } >/dev/null 2>&1
31
+ if [[ "$passes" -ne $((_iv_p + 1)) || "$fails" -ne $((_iv_f + 1)) || "${#FAILED[@]}" -ne $((_iv_n + 1)) ]]; then
32
+ printf '[FATAL] instrument self-test: the verdict helpers did not both record\n' >&2; exit 1
33
+ fi
34
+ passes=0; fails=0; FAILED=(); CASES_RUN=0
35
+
36
+ [[ -f "$SUT" ]] || { echo "[FATAL] SUT not found at $SUT" >&2; exit 1; }
37
+
38
+ assert_fixture_dir() {
39
+ case "${1-}" in
40
+ "") printf 'FATAL: fixture dir is EMPTY; git -C "" would operate on %s\n' "$PWD" >&2; exit 2 ;;
41
+ */../*|*/..) printf 'FATAL: fixture dir %s contains ..; refusing\n' "$1" >&2; exit 2 ;;
42
+ /proc/*|/sys/*|/dev/*) printf 'FATAL: fixture dir %s is a synthetic-fs path; refusing\n' "$1" >&2; exit 2 ;;
43
+ /|//|/.) printf 'FATAL: fixture dir resolves to the filesystem root; refusing\n' >&2; exit 2 ;;
44
+ /*) : ;;
45
+ *) printf 'FATAL: fixture dir %s is RELATIVE; refusing\n' "$1" >&2; exit 2 ;;
46
+ esac
47
+ }
48
+
49
+ SANDBOX="$(mktemp -d)"; assert_fixture_dir "$SANDBOX"
50
+ trap 'rm -rf "$SANDBOX"' EXIT
51
+ # The resolver stages sources under XDG_CACHE_HOME; keep that inside the sandbox too.
52
+ export XDG_CACHE_HOME="$SANDBOX/xdg-cache"
53
+
54
+ MODEL="knowledge-base/engineering/architecture/diagrams/model.likec4.json"
55
+ SRC="knowledge-base/engineering/architecture/diagrams/model.c4"
56
+ _git() { git -C "$1" -c user.email=t@t -c user.name=t "${@:2}"; }
57
+
58
+ # mkfix <name> <conflict-kind> — a repo with a real `origin` remote (a local bare clone, so the
59
+ # push path is exercised for real rather than stubbed) and a conflict of the requested kind.
60
+ mkfix() {
61
+ local name="$1" kind="$2"
62
+ local root="$SANDBOX/$name"; assert_fixture_dir "$root"
63
+ local up="$root/upstream.git" wt="$root/wt"
64
+ mkdir -p "$up" "$wt"
65
+ git init -q --bare "$up"
66
+
67
+ mkdir -p "$wt/knowledge-base/engineering/architecture/diagrams" \
68
+ "$wt/plugins/soleur/scripts" "$wt/plugins/soleur/.claude-plugin"
69
+ printf 'first\nx\nlast\n' > "$wt/$SRC"
70
+ printf '{"v":"base"}\n' > "$wt/$MODEL"
71
+ printf 'readme base\n' > "$wt/README.md"
72
+ # BOTH scripts are COPIED INTO THE FIXTURE, and for sync-pr-behind.sh that is mandatory,
73
+ # not stylistic: it resolves its own repo root from ${BASH_SOURCE[0]}/../../.. and `cd`s
74
+ # there. Run from the tracked path it would operate on the REAL repository regardless of
75
+ # this fixture -- measured: the first run of this suite reported the developer's own branch
76
+ # name and exited 6 against the live worktree. Copying it makes that walk land in $wt.
77
+ cp "$SCRIPT_DIR/sync-pr-behind.sh" "$wt/plugins/soleur/scripts/"
78
+ cp "$SCRIPT_DIR/resolve-regenerable-conflicts.sh" "$wt/plugins/soleur/scripts/"
79
+ # The resolver runs the renderer BESIDE ITSELF (ADR-235 amendment), so the stub goes there
80
+ # with a plugin.json the resolver's identity check accepts. It takes the real renderer's
81
+ # `--root <staging> --out <file>` argv as the resolver passes it, and refuses any other shape.
82
+ printf '{\n "name": "soleur"\n}\n' > "$wt/plugins/soleur/.claude-plugin/plugin.json"
83
+ cat > "$wt/plugins/soleur/scripts/render-c4-model.sh" <<STUB
84
+ #!/usr/bin/env bash
85
+ set -euo pipefail
86
+ [[ "\$#" -eq 4 && "\$1" == "--root" && -d "\$2" && "\$3" == "--out" ]] || { echo "stub renderer: bad argv: \$*" >&2; exit 64; }
87
+ R="\$2"
88
+ printf '{"from":"%s|%s"}\n' "\$(head -1 "\$R/$SRC")" "\$(tail -1 "\$R/$SRC")" | tee "\$4" >/dev/null
89
+ STUB
90
+ chmod +x "$wt/plugins/soleur/scripts/render-c4-model.sh"
91
+ _git "$wt" init -q -b main
92
+ # Identity in LOCAL config, not only on `_git`'s `-c`: the SUT's own merge runs in this
93
+ # repo and reads config, so without these it only had an identity where the developer's
94
+ # GLOBAL config supplied one. Same defect as resolve-regenerable-conflicts.test.sh, which
95
+ # failed 14 rows on a CI runner (#8384, run 35588718251); this suite was found by sweeping
96
+ # the PR's suites under HOME=$(mktemp -d) GIT_CONFIG_GLOBAL=/dev/null.
97
+ git -C "$wt" config user.email t@t
98
+ git -C "$wt" config user.name t
99
+ _git "$wt" remote add origin "$up"
100
+ _git "$wt" add -A >/dev/null; _git "$wt" commit -q -m base
101
+ _git "$wt" push -q origin main
102
+
103
+ _git "$wt" checkout -q -b feature
104
+ sed -i 's/^last$/last-FEATURE/' "$wt/$SRC"
105
+ printf '{"v":"feature"}\n' > "$wt/$MODEL"
106
+ [[ "$kind" == "unresolvable" ]] && printf 'readme FEATURE\n' > "$wt/README.md"
107
+ _git "$wt" add -A >/dev/null; _git "$wt" commit -q -m feature
108
+ _git "$wt" push -q -u origin feature
109
+
110
+ _git "$wt" checkout -q main
111
+ sed -i 's/^first$/first-MAIN/' "$wt/$SRC"
112
+ printf '{"v":"main"}\n' > "$wt/$MODEL"
113
+ [[ "$kind" == "unresolvable" ]] && printf 'readme MAIN\n' > "$wt/README.md"
114
+ _git "$wt" add -A >/dev/null; _git "$wt" commit -q -m main
115
+ _git "$wt" push -q origin main
116
+ _git "$wt" checkout -q feature
117
+
118
+ # STRICT gh stub: answers only the query the SUT is expected to make, refuses anything else.
119
+ mkdir -p "$root/bin"
120
+ cat > "$root/bin/gh" <<'GH'
121
+ #!/usr/bin/env bash
122
+ # The merge-queue read (#9454) is the one other request the SUT makes: it asks
123
+ # `gh api graphql ... isInMergeQueue` and expects `not_queued` / `queued` back (--jq).
124
+ # This suite's PR is never queued; a graphql call WITHOUT the queue fields is still a miss.
125
+ if [[ "$1 $2" == "api graphql" ]]; then
126
+ case "$*" in
127
+ *isInMergeQueue*mergeQueueEntry*) echo not_queued; exit 0 ;;
128
+ *) echo "STUB-MISS: gh api graphql without the merge-queue fields: $*" >&2; exit 64 ;;
129
+ esac
130
+ fi
131
+ if [[ "$1 $2" != "pr view" ]]; then
132
+ echo "STUB-MISS: unexpected gh invocation: $*" >&2; exit 64
133
+ fi
134
+ # The standalone loop first checks the PR's head branch (kind=wrong_branch, exit 12).
135
+ # Answer it with the fixture branch; it is not a state read, so it is not counted.
136
+ for a in "$@"; do [[ "$a" == "headRefName" ]] && { echo "feature"; exit 0; }; done
137
+ for a in "$@"; do [[ "$a" == "state,mergeStateStatus" ]] && found=1; done
138
+ if [[ -z "${found:-}" ]]; then
139
+ echo "STUB-MISS: gh pr view without the expected --json fields: $*" >&2; exit 64
140
+ fi
141
+ n="$(cat "${GH_CALLS:?}" 2>/dev/null || echo 0)"; echo $((n + 1)) > "$GH_CALLS"
142
+ if [[ "$n" -eq 0 ]]; then echo "OPEN DIRTY"; else echo "OPEN CLEAN"; fi
143
+ GH
144
+ chmod +x "$root/bin/gh"
145
+ printf '%s' "$root"
146
+ }
147
+
148
+ run_sut() {
149
+ # SPLIT, not `local root="$1" wt="$root/wt"`: within one `local` statement the later
150
+ # assignment does not see the earlier name, so under `set -u` that form aborts the function
151
+ # with "root: unbound variable" -- and the caller reads the empty output as a SUT that
152
+ # printed nothing, which looks exactly like the bug this suite is here to detect.
153
+ local root="$1"
154
+ local wt="$root/wt"
155
+ local out rc=0
156
+ out="$(cd "$wt" && GH_CALLS="$root/gh.calls" PATH="$root/bin:$PATH" \
157
+ bash "$wt/plugins/soleur/scripts/sync-pr-behind.sh" 123 2>&1)" || rc=$?
158
+ printf '%s\n%s' "$out" "$rc"
159
+ }
160
+ sut_rc() { tail -n1 <<<"$1"; }
161
+ sut_out() { sed '$d' <<<"$1"; }
162
+
163
+ # RELOCATION SELF-TEST. The failure mode this guards is silent and total: a SUT that walks
164
+ # to the real repo answers every case from a tree the fixture never built, and the verdicts
165
+ # look ordinary. Require the fixture's own branch name in the output before reading anything.
166
+ _rt_root="$(mkfix relocation resolvable)"
167
+ _rt_out="$(sut_out "$(run_sut "$_rt_root")")"
168
+ if ! grep -q 'branch: feature' <<<"$_rt_out"; then
169
+ printf '[FATAL] relocation self-test: the SUT did not report the fixture branch.\n' >&2
170
+ printf ' It is operating on some other repository, so every case below is void.\n' >&2
171
+ printf ' got: %s\n' "$_rt_out" >&2
172
+ exit 1
173
+ fi
174
+
175
+ echo "=== sync-pr-behind: regenerable-conflict arm ==="
176
+
177
+ # ── rc 0: the conflict is regenerable -> merged, regenerated, pushed ───────────────────────
178
+ echo ""
179
+ echo "--- resolver rc 0: merge is completed and pushed ---"
180
+ root="$(mkfix ok resolvable)"; wt="$root/wt"
181
+ res="$(run_sut "$root")"
182
+ CASES_RUN=$((CASES_RUN + 1))
183
+ [[ "$(sut_rc "$res")" == "0" ]] && pass "exits 0 on a regenerable conflict" \
184
+ || fail "exited $(sut_rc "$res"): $(sut_out "$res")"
185
+ CASES_RUN=$((CASES_RUN + 1))
186
+ if grep -q 'regenerable conflict resolved' <<<"$(sut_out "$res")"; then
187
+ pass "reports that the regenerable path was taken"
188
+ else
189
+ fail "the regenerable arm is invisible in the output: $(sut_out "$res")"
190
+ fi
191
+ CASES_RUN=$((CASES_RUN + 1))
192
+ [[ "$(cat "$wt/$MODEL")" == *'first-MAIN|last-FEATURE'* ]] \
193
+ && pass "the artifact was regenerated from the MERGED sources" \
194
+ || fail "artifact is $(cat "$wt/$MODEL") — regen did not see the merged tree"
195
+ CASES_RUN=$((CASES_RUN + 1))
196
+ # The merge must have reached the REMOTE: this is what distinguishes "resolved" from
197
+ # "resolved locally and silently not pushed", and the resolver deliberately never pushes.
198
+ if _git "$root/upstream.git" rev-parse feature >/dev/null 2>&1 \
199
+ && [[ "$(_git "$wt" rev-parse feature)" == "$(_git "$root/upstream.git" rev-parse feature)" ]]; then
200
+ pass "the merge commit was pushed (the caller owns the push, not the resolver)"
201
+ else
202
+ fail "the remote feature ref does not match local HEAD — the merge was never pushed"
203
+ fi
204
+ CASES_RUN=$((CASES_RUN + 1))
205
+ [[ -z "$(_git "$wt" status --porcelain)" ]] && pass "the worktree is clean afterwards" \
206
+ || fail "worktree dirty: $(_git "$wt" status --porcelain)"
207
+
208
+ # ── non-zero: a non-regenerable conflict is refused exactly as before ──────────────────────
209
+ echo ""
210
+ echo "--- resolver non-zero: unchanged exit 6, tree untouched ---"
211
+ root="$(mkfix bad unresolvable)"; wt="$root/wt"
212
+ head_before="$(_git "$wt" rev-parse HEAD)"
213
+ res="$(run_sut "$root")"
214
+ CASES_RUN=$((CASES_RUN + 1))
215
+ [[ "$(sut_rc "$res")" == "6" ]] && pass "exits 6 on a non-regenerable conflict" \
216
+ || fail "expected exit 6, got $(sut_rc "$res"): $(sut_out "$res")"
217
+ CASES_RUN=$((CASES_RUN + 1))
218
+ [[ "$(_git "$wt" rev-parse HEAD)" == "$head_before" ]] && pass "HEAD did not move" \
219
+ || fail "HEAD moved on a conflict that should have been refused"
220
+ CASES_RUN=$((CASES_RUN + 1))
221
+ [[ -z "$(_git "$wt" status --porcelain)" ]] && pass "the tree is clean (merge aborted)" \
222
+ || fail "tree left dirty: $(_git "$wt" status --porcelain)"
223
+ CASES_RUN=$((CASES_RUN + 1))
224
+ if grep -q 'manual resolution required' <<<"$(sut_out "$res")"; then
225
+ pass "reports that manual resolution is required"
226
+ else
227
+ fail "the refusal is not reported: $(sut_out "$res")"
228
+ fi
229
+ CASES_RUN=$((CASES_RUN + 1))
230
+ if grep -q 'STUB-MISS' <<<"$(sut_out "$res")"; then
231
+ fail "the gh stub was called in a way it did not expect — the fixture is not exercising the real request shape"
232
+ else
233
+ pass "no STUB-MISS: the SUT queried gh exactly as the stub expects"
234
+ fi
235
+
236
+ echo ""
237
+ echo "cases_run=$CASES_RUN passes=$passes fails=$fails ledger=${#FAILED[@]}"
238
+ _min_cases=10
239
+ if [[ "$CASES_RUN" -lt "$_min_cases" ]]; then
240
+ printf '[FATAL] assertion floor: only %s case(s) ran, floor is %s\n' "$CASES_RUN" "$_min_cases" >&2; exit 1
241
+ fi
242
+ if [[ $((passes + fails)) -ne "$CASES_RUN" ]]; then
243
+ printf '[FATAL] %s verdicts for %s cases\n' "$((passes + fails))" "$CASES_RUN" >&2; exit 1
244
+ fi
245
+ if [[ "${#FAILED[@]}" -ne "$fails" ]]; then
246
+ printf '[FATAL] ledger/counter disagree: %s vs %s\n' "${#FAILED[@]}" "$fails" >&2; exit 1
247
+ fi
248
+ if [[ "${#FAILED[@]}" -ne 0 ]]; then
249
+ printf '[FATAL] %s failing assertion(s):\n' "${#FAILED[@]}" >&2
250
+ printf ' - %s\n' "${FAILED[@]}" >&2; exit 1
251
+ fi
252
+ echo "sync-pr-behind: all $passes assertions passed"
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env bash
2
+ # taste-profile-update.sh — context-keyed design taste-profile writer/validator
3
+ # (#5990 · FR7 · ADR-090). Rides FR6 declarative context-injection (ADR-086):
4
+ # the committed taste-profile.md is agent-writable content, so per ADR-086
5
+ # §Consequences (content-trust ≠ path-trust) THIS helper is the sanitizing
6
+ # boundary — every model-supplied token (context, axis, value, date) is validated
7
+ # before it reaches the committed file that FR6 re-injects.
8
+ #
9
+ # Modes:
10
+ # write: taste-profile-update.sh <profile.md> <context> <axis> <value> <today-YYYY-MM-DD>
11
+ # validate: taste-profile-update.sh --validate <profile.md>
12
+ #
13
+ # Model: entries keyed by (context, axis) → value, ordered by RECENCY
14
+ # (last_reinforced, tie-break reinforce_count). No numeric weighting/scoring.
15
+ # Contradiction fires only within the SAME (context, axis); resolution = supersede,
16
+ # logged to contradictions[]. Automated writes bump `last_updated` only — never
17
+ # `last_reviewed` (freshness convention / context-reviewed-gate.sh).
18
+ #
19
+ # jq + bash only. Whole-file re-render from the parsed frontmatter + transformed
20
+ # JSON block (the machine block is the source of truth; the human tables are
21
+ # regenerated). Atomic tmp+mv; original preserved on any failure.
22
+ set -uo pipefail
23
+
24
+ # --- allowlists / sanitizers (the content-trust boundary) --------------------
25
+ CONTEXT_ALLOW=" landing-page marketing-site dashboard app-ui docs email component "
26
+ AXIS_ALLOW=" aesthetic-direction "
27
+ # value = a short lowercase-hyphen aesthetic-direction slug (≤40 chars). The closed
28
+ # charset + length cap is the injection defense: no whitespace/punctuation means a
29
+ # value can never encode imperative prose that could steer a future FR6-primed session.
30
+ VALUE_RE='^[a-z][a-z0-9-]{0,39}$'
31
+ DATE_RE='^[0-9]{4}-[0-9]{2}-[0-9]{2}$'
32
+
33
+ die() { printf 'taste-profile-update: %s\n' "$1" >&2; exit 1; }
34
+
35
+ extract_json() {
36
+ # Emit the JSON between the data markers, dropping the ``` fences.
37
+ awk '/taste-profile:data:start/{f=1;next} /taste-profile:data:end/{f=0} f' "$1" \
38
+ | sed -e '/^```/d'
39
+ }
40
+
41
+ # Frontmatter-scoped field read (house `c==1` idiom — only the block between the
42
+ # first two `---` lines, so a body line beginning with the key never matches).
43
+ fm_field() { awk -F': ' -v k="$1" 'FNR==1{c=0} /^---$/{c++; next} c==1 && $0 ~ "^"k":" {print $2; exit}' "$2"; }
44
+
45
+ validate_json() {
46
+ # $1 = json string. Returns 0 iff EVERY entry AND contradiction is well-formed
47
+ # (same allowlists/regex a fresh write enforces). This is the consumer read-path
48
+ # trust gate (ADR-090): it must cover the whole machine block, not just entries.
49
+ local j="$1"
50
+ echo "$j" | jq -e '.schema == 1 and (.entries|type=="array") and (.contradictions|type=="array")' >/dev/null 2>&1 || return 1
51
+ local bad
52
+ bad=$(echo "$j" | jq -r \
53
+ --arg ctxs "$CONTEXT_ALLOW" --arg axes "$AXIS_ALLOW" \
54
+ --arg valre "$VALUE_RE" --arg datere "$DATE_RE" '
55
+ def ok_ctx($c): ($ctxs | contains(" " + $c + " "));
56
+ def ok_axis($a): ($axes | contains(" " + $a + " "));
57
+ ( [ .entries[]
58
+ | select(
59
+ ( ok_ctx(.context) | not ) or ( ok_axis(.axis) | not )
60
+ or ( (.value|type) != "string" ) or ( .value | test($valre) | not )
61
+ or ( .last_reinforced | test($datere) | not )
62
+ or ( (.reinforce_count|type) != "number" ) or ( .reinforce_count < 1 )
63
+ ) ] | length )
64
+ + ( [ .contradictions[]
65
+ | select(
66
+ ( ok_ctx(.context) | not ) or ( ok_axis(.axis) | not )
67
+ or ( (.old_value|type) != "string" ) or ( .old_value | test($valre) | not )
68
+ or ( (.new_value|type) != "string" ) or ( .new_value | test($valre) | not )
69
+ or ( .date | test($datere) | not )
70
+ or ( (.old_count|type) != "number" )
71
+ ) ] | length )' 2>/dev/null)
72
+ [[ "$bad" == "0" ]] || return 1
73
+ return 0
74
+ }
75
+
76
+ render_file() {
77
+ # $1 profile path, $2 preserved last_reviewed, $3 review_cadence, $4 owner,
78
+ # $5 today (new last_updated), $6 json
79
+ local out reviewed cadence owner today json tables flags
80
+ out="$1"; reviewed="$2"; cadence="$3"; owner="$4"; today="$5"; json="$6"
81
+ # Recency order: most-recent first, higher reinforce_count breaks a same-date tie.
82
+ tables=$(echo "$json" | jq -r '
83
+ if (.entries|length)==0 then "_None yet._"
84
+ else (["| context | axis | value | last_reinforced | reinforced |",
85
+ "|---|---|---|---|---|"]
86
+ + ( .entries | sort_by([.last_reinforced, .reinforce_count]) | reverse
87
+ | map("| \(.context) | \(.axis) | \(.value) | \(.last_reinforced) | \(.reinforce_count) |") ))
88
+ | join("\n")
89
+ end') || return 1
90
+ flags=$(echo "$json" | jq -r '
91
+ if (.contradictions|length)==0 then "_None yet._"
92
+ else ( .contradictions | sort_by(.date) | reverse
93
+ | map("- \(.date) — `\(.context)`/`\(.axis)`: `\(.old_value)` (reinforced \(.old_count)×) superseded by `\(.new_value)`") )
94
+ | join("\n")
95
+ end') || return 1
96
+ local compact
97
+ compact=$(echo "$json" | jq -c '.') || return 1
98
+ cat > "$out" <<EOF
99
+ ---
100
+ last_updated: $today
101
+ last_reviewed: $reviewed
102
+ review_cadence: $cadence
103
+ owner: $owner
104
+ ---
105
+ # Design Taste Profile
106
+
107
+ Learned operator design preferences, keyed by \`(context, axis)\` and ordered by
108
+ recency. Loaded into design sessions via FR6 (\`frontend-design\` skill \`context_queries\`)
109
+ and a direct Read (\`ux-design-lead\` agent). See ADR-090.
110
+
111
+ <!-- Machine block owned by plugins/soleur/scripts/taste-profile-update.sh — do not hand-edit. -->
112
+ <!-- taste-profile:data:start -->
113
+ \`\`\`json
114
+ $compact
115
+ \`\`\`
116
+ <!-- taste-profile:data:end -->
117
+
118
+ ## Reinforced Aesthetics
119
+
120
+ $tables
121
+
122
+ ## Contradiction Flags
123
+
124
+ $flags
125
+ EOF
126
+ }
127
+
128
+ # --- validate mode -----------------------------------------------------------
129
+ if [[ "${1:-}" == "--validate" ]]; then
130
+ profile="${2:-}"
131
+ [[ -n "$profile" && -f "$profile" ]] || die "validate: profile not found: ${2:-<none>}"
132
+ json="$(extract_json "$profile")"
133
+ [[ -n "$json" ]] || die "validate: no machine block in $profile"
134
+ validate_json "$json" || die "validate: profile failed schema/allowlist checks"
135
+ exit 0
136
+ fi
137
+
138
+ # --- write mode --------------------------------------------------------------
139
+ [[ $# -eq 5 ]] || die "usage: <profile.md> <context> <axis> <value> <today> | --validate <profile.md>"
140
+ profile="$1"; context="$2"; axis="$3"; value="$4"; today="$5"
141
+ [[ -f "$profile" ]] || die "profile not found: $profile"
142
+
143
+ # Token validation — the ADR-086 content-trust boundary. Reject → exit non-zero,
144
+ # original untouched (no write attempted).
145
+ [[ "$CONTEXT_ALLOW" == *" $context "* ]] || die "context not in allowlist: $context"
146
+ [[ "$AXIS_ALLOW" == *" $axis "* ]] || die "axis not in allowlist: $axis"
147
+ [[ "$value" =~ $VALUE_RE ]] || die "value must match $VALUE_RE"
148
+ [[ "$today" =~ $DATE_RE ]] || die "date must match $DATE_RE"
149
+
150
+ json="$(extract_json "$profile")"
151
+ [[ -n "$json" ]] || die "no machine block in $profile"
152
+ validate_json "$json" || die "existing profile failed validation (refusing to write over a corrupt file)"
153
+
154
+ new_json="$(echo "$json" | jq -c --arg ctx "$context" --arg axis "$axis" --arg val "$value" --arg today "$today" '
155
+ ( .entries | map(select(.context==$ctx and .axis==$axis)) | .[0] ) as $ex
156
+ | ( if ($ex != null) and ($ex.value != $val)
157
+ then .contradictions += [{context:$ctx, axis:$axis, old_value:$ex.value, new_value:$val, old_count:$ex.reinforce_count, date:$today}]
158
+ else . end )
159
+ | .entries = (
160
+ ( .entries | map(select((.context==$ctx and .axis==$axis) | not)) )
161
+ + [ { context:$ctx, axis:$axis, value:$val, last_reinforced:$today,
162
+ reinforce_count: ( if ($ex != null and $ex.value==$val) then ($ex.reinforce_count + 1) else 1 end ) } ]
163
+ )
164
+ ')" || die "jq transform failed"
165
+ [[ -n "$new_json" ]] || die "jq produced empty output"
166
+
167
+ reviewed="$(fm_field last_reviewed "$profile")"
168
+ cadence="$(fm_field review_cadence "$profile")"
169
+ owner="$(fm_field owner "$profile")"
170
+
171
+ # lint-trap-ownership: ok — allocates "${profile}.tmp.XXXXXX" BESIDE the target
172
+ # file (never /tmp); mv'd into place on success, rm -f'd on render failure.
173
+ # Residual is one sibling file per SIGKILL inside a two-statement window.
174
+ tmp="$(mktemp "${profile}.tmp.XXXXXX")" || die "mktemp failed"
175
+ if render_file "$tmp" "$reviewed" "$cadence" "$owner" "$today" "$new_json"; then
176
+ mv -f "$tmp" "$profile"
177
+ else
178
+ rm -f "$tmp"
179
+ die "render failed; original preserved"
180
+ fi
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env bash
2
+ # taste-profile-update.test.sh — fixture harness for the context-keyed taste-profile
3
+ # helper (#5990 · FR7 · ADR-090). Pattern mirrors .claude/hooks/skill-context-queries.test.sh.
4
+ #
5
+ # jq + bash only. Each test builds a fresh fixture profile in a temp dir, runs the
6
+ # helper, and asserts on the resulting file (or exit code). No network, no git needed.
7
+ set -uo pipefail
8
+
9
+ SCRIPT_DIR="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
10
+ HELPER="$SCRIPT_DIR/taste-profile-update.sh"
11
+
12
+ pass=0
13
+ fail=0
14
+ pass() { printf ' \033[0;32mPASS\033[0m %s\n' "$1"; pass=$((pass + 1)); }
15
+ fail() { printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; fail=$((fail + 1)); }
16
+
17
+ TMP_ROOT="$(mktemp -d)"
18
+ trap 'rm -rf "$TMP_ROOT"' EXIT
19
+
20
+ # Build a fresh seed profile; echoes its path.
21
+ mk_profile() {
22
+ local d p
23
+ d="$(mktemp -d "$TMP_ROOT/prof.XXXXXX")"
24
+ p="$d/taste-profile.md"
25
+ cat > "$p" <<'EOF'
26
+ ---
27
+ last_updated: 2026-07-01
28
+ last_reviewed: 2026-07-01
29
+ review_cadence: quarterly
30
+ owner: CPO
31
+ ---
32
+ # Design Taste Profile
33
+
34
+ <!-- Machine block owned by plugins/soleur/scripts/taste-profile-update.sh — do not hand-edit. -->
35
+ <!-- taste-profile:data:start -->
36
+ ```json
37
+ {"schema":1,"entries":[],"contradictions":[]}
38
+ ```
39
+ <!-- taste-profile:data:end -->
40
+
41
+ ## Reinforced Aesthetics
42
+
43
+ _None yet._
44
+
45
+ ## Contradiction Flags
46
+
47
+ _None yet._
48
+ EOF
49
+ echo "$p"
50
+ }
51
+
52
+ # Extract the JSON machine block from a profile file.
53
+ data_of() {
54
+ awk '/taste-profile:data:start/{f=1;next} /taste-profile:data:end/{f=0} f' "$1" \
55
+ | sed -e '/^```/d'
56
+ }
57
+
58
+ echo "== taste-profile-update.sh =="
59
+
60
+ # 1. Upsert + reinforce (reinforce_count increments; recency date set)
61
+ p="$(mk_profile)"
62
+ bash "$HELPER" "$p" dashboard aesthetic-direction minimalist 2026-07-05 >/dev/null 2>&1
63
+ bash "$HELPER" "$p" dashboard aesthetic-direction minimalist 2026-07-06 >/dev/null 2>&1
64
+ n=$(data_of "$p" | jq '[.entries[] | select(.context=="dashboard" and .value=="minimalist")] | length' 2>/dev/null)
65
+ c=$(data_of "$p" | jq '.entries[] | select(.context=="dashboard" and .value=="minimalist") | .reinforce_count' 2>/dev/null)
66
+ lr=$(data_of "$p" | jq -r '.entries[] | select(.context=="dashboard" and .value=="minimalist") | .last_reinforced' 2>/dev/null)
67
+ if [[ "$n" == "1" && "$c" == "2" && "$lr" == "2026-07-06" ]]; then
68
+ pass "upsert+reinforce (one entry, count=2, recency updated)"
69
+ else fail "upsert+reinforce (got n=$n count=$c lr=$lr)"; fi
70
+
71
+ # 2. Same-context contradiction: differing value → contradictions[] entry + supersede
72
+ p="$(mk_profile)"
73
+ bash "$HELPER" "$p" landing-page aesthetic-direction editorial 2026-07-05 >/dev/null 2>&1
74
+ bash "$HELPER" "$p" landing-page aesthetic-direction maximalist 2026-07-06 >/dev/null 2>&1
75
+ cval=$(data_of "$p" | jq -r '.entries[] | select(.context=="landing-page") | .value' 2>/dev/null)
76
+ flag=$(data_of "$p" | jq '[.contradictions[] | select(.context=="landing-page" and .old_value=="editorial" and .new_value=="maximalist")] | length' 2>/dev/null)
77
+ if [[ "$cval" == "maximalist" && "$flag" == "1" ]]; then
78
+ pass "same-context contradiction flag fires + supersedes (old=editorial→new=maximalist)"
79
+ else fail "same-context contradiction (got value=$cval flag=$flag)"; fi
80
+
81
+ # 3. Cross-context is NOT a contradiction (dashboard + landing coexist)
82
+ p="$(mk_profile)"
83
+ bash "$HELPER" "$p" dashboard aesthetic-direction minimalist 2026-07-05 >/dev/null 2>&1
84
+ bash "$HELPER" "$p" landing-page aesthetic-direction maximalist 2026-07-06 >/dev/null 2>&1
85
+ ecount=$(data_of "$p" | jq '.entries | length' 2>/dev/null)
86
+ ccount=$(data_of "$p" | jq '.contradictions | length' 2>/dev/null)
87
+ if [[ "$ecount" == "2" && "$ccount" == "0" ]]; then
88
+ pass "cross-context NON-contradiction (2 entries, 0 flags)"
89
+ else fail "cross-context (got entries=$ecount contradictions=$ccount)"; fi
90
+
91
+ # 4. Reject out-of-allowlist context (preserve original)
92
+ p="$(mk_profile)"; before="$(cat "$p")"
93
+ if bash "$HELPER" "$p" 'prod; rm -rf /' aesthetic-direction minimalist 2026-07-05 >/dev/null 2>&1; then
94
+ fail "reject bad context (helper returned 0)"
95
+ else
96
+ [[ "$(cat "$p")" == "$before" ]] && pass "reject bad context + preserve original" || fail "bad context mutated file"
97
+ fi
98
+
99
+ # 5. Reject out-of-allowlist axis
100
+ p="$(mk_profile)"; before="$(cat "$p")"
101
+ if bash "$HELPER" "$p" dashboard color-temperature minimalist 2026-07-05 >/dev/null 2>&1; then
102
+ fail "reject bad axis (helper returned 0)"
103
+ else
104
+ [[ "$(cat "$p")" == "$before" ]] && pass "reject out-of-allowlist axis + preserve" || fail "bad axis mutated file"
105
+ fi
106
+
107
+ # 6. Reject metachar/whitespace value
108
+ p="$(mk_profile)"; before="$(cat "$p")"
109
+ if bash "$HELPER" "$p" dashboard aesthetic-direction 'max; touch /tmp/x' 2026-07-05 >/dev/null 2>&1; then
110
+ fail "reject metachar value (helper returned 0)"
111
+ else
112
+ [[ "$(cat "$p")" == "$before" ]] && pass "reject metachar value + preserve" || fail "bad value mutated file"
113
+ fi
114
+
115
+ # 7. Reject malformed date
116
+ p="$(mk_profile)"; before="$(cat "$p")"
117
+ if bash "$HELPER" "$p" dashboard aesthetic-direction minimalist 'yesterday' >/dev/null 2>&1; then
118
+ fail "reject bad date (helper returned 0)"
119
+ else
120
+ [[ "$(cat "$p")" == "$before" ]] && pass "reject malformed date + preserve" || fail "bad date mutated file"
121
+ fi
122
+
123
+ # 8. Freshness: last_updated bumped, last_reviewed byte-unchanged
124
+ p="$(mk_profile)"
125
+ rev_before=$(awk -F': ' '/^last_reviewed:/{print $2; exit}' "$p")
126
+ bash "$HELPER" "$p" docs aesthetic-direction editorial 2026-07-09 >/dev/null 2>&1
127
+ upd=$(awk -F': ' '/^last_updated:/{print $2; exit}' "$p")
128
+ rev_after=$(awk -F': ' '/^last_reviewed:/{print $2; exit}' "$p")
129
+ if [[ "$upd" == "2026-07-09" && "$rev_after" == "$rev_before" ]]; then
130
+ pass "freshness: last_updated bumped, last_reviewed unchanged"
131
+ else fail "freshness (last_updated=$upd last_reviewed=$rev_after expected_rev=$rev_before)"; fi
132
+
133
+ # 9. --validate: passes on a clean profile, fails on a tampered one
134
+ p="$(mk_profile)"
135
+ bash "$HELPER" "$p" app-ui aesthetic-direction brutalist 2026-07-05 >/dev/null 2>&1
136
+ if bash "$HELPER" --validate "$p" >/dev/null 2>&1; then pass "--validate passes on clean profile"; else fail "--validate rejected a clean profile"; fi
137
+ # tamper: inject an out-of-allowlist axis directly into the JSON
138
+ python3 - "$p" <<'PY' 2>/dev/null || true
139
+ import re,sys,json
140
+ f=sys.argv[1]; s=open(f).read()
141
+ m=re.search(r'```json\n(.*?)\n```', s, re.S)
142
+ d=json.loads(m.group(1)); d["entries"].append({"context":"docs","axis":"evil-axis","value":"x","last_reinforced":"2026-07-05","reinforce_count":1})
143
+ s=s[:m.start(1)]+json.dumps(d)+s[m.end(1):]; open(f,"w").write(s)
144
+ PY
145
+ if bash "$HELPER" --validate "$p" >/dev/null 2>&1; then fail "--validate passed a tampered profile"; else pass "--validate fails on tampered profile"; fi
146
+
147
+ # 9b. --validate also covers contradictions[] (not just entries[]) — the consumer
148
+ # read-path trust gate must certify the whole machine block (security P3-1 / user-impact F2).
149
+ p="$(mk_profile)"
150
+ bash "$HELPER" "$p" landing-page aesthetic-direction editorial 2026-07-05 >/dev/null 2>&1
151
+ python3 - "$p" <<'PY' 2>/dev/null || true
152
+ import re,sys,json
153
+ f=sys.argv[1]; s=open(f).read()
154
+ m=re.search(r'```json\n(.*?)\n```', s, re.S)
155
+ d=json.loads(m.group(1)); d["contradictions"].append({"context":"landing-page","axis":"aesthetic-direction","old_value":"editorial; rm -rf /","new_value":"maximalist","old_count":1,"date":"2026-07-06"})
156
+ s=s[:m.start(1)]+json.dumps(d)+s[m.end(1):]; open(f,"w").write(s)
157
+ PY
158
+ if bash "$HELPER" --validate "$p" >/dev/null 2>&1; then fail "--validate passed a poisoned contradictions[] entry"; else pass "--validate fails on poisoned contradictions[] (whole-block coverage)"; fi
159
+
160
+ # 10. No decay/confidence tokens in the helper source (recency, not numeric decay)
161
+ if grep -qiE 'halflife|confidence|decay_' "$HELPER" 2>/dev/null; then
162
+ fail "helper contains decay/confidence tokens"
163
+ else pass "helper is recency-only (no decay/confidence tokens)"; fi
164
+
165
+ echo ""
166
+ echo "== $pass passed, $fail failed =="
167
+ [[ "$fail" -eq 0 ]] || exit 1
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env bash
2
+ # write-budget-marker.sh <dim> — write the classified `budget-capped` artifact
3
+ # for a ship/merge-pr phase-7 poll gate STOP (#9403). Emits nothing; exits 0
4
+ # always (fail-open like the tally itself). Extracted so the ship↔merge-pr
5
+ # mirror carries one implementation, not a byte-copied block.
6
+ set -uo pipefail
7
+
8
+ dim="${1:?usage: write-budget-marker.sh <dim>}"
9
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
10
+
11
+ show="$(bash "$ROOT/scripts/pipeline-tally.sh" show 2>/dev/null || true)"
12
+ cnt="$(printf '%s\n' "$show" | grep -o "${dim}=[0-9]*" | head -1 | cut -d= -f2 || true)"
13
+ cap="$(printf '%s\n' "$show" | grep -o "cap:${dim}=[0-9]*" | head -1 | cut -d= -f2 || true)"
14
+ # $() strips the newline before tr sees it; tr inside the substitution would
15
+ # map it to a stray '-'. Marker lands in the specs/<feature>/ dir the resume
16
+ # contract greps — the same shape the skills' classified-stop blocks write.
17
+ b="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
18
+ ss="knowledge-base/project/specs/$(printf '%s' "${b:-HEAD}" | tr -c 'A-Za-z0-9._-' '-')"
19
+ mkdir -p "$ss" 2>/dev/null \
20
+ && printf 'status: budget-capped\nbudget-capped: %s=%s/%s\nresume: bash "%s/scripts/pipeline-tally.sh" init --max-%s <N>, then re-run the skill\n' \
21
+ "$dim" "${cnt:-0}" "${cap:-0}" "$ROOT" "$(printf '%s' "$dim" | tr '_' '-')" \
22
+ >> "$ss/session-state.md" || true
23
+ exit 0