@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,443 @@
1
+ #!/usr/bin/env python3
2
+ """Redact credential-shaped values out of an accessibility snapshot (#7947).
3
+
4
+ Reads a snapshot on stdin, writes the redacted form to stdout.
5
+
6
+ WHY THIS IS NAME-BASED AND NOT STRUCTURAL
7
+ -----------------------------------------
8
+ Phase 0.1 measured both leaking surfaces (record:
9
+ knowledge-base/project/specs/feat-one-shot-7946-7947-sentry-org-token-and-snapshot-redaction/phase-0-measurement.md).
10
+ Neither `agent-browser` 0.22.3 nor the Playwright MCP serializes the input's
11
+ `type=` into the tree -- a password box, a readonly token box and an email box
12
+ all render as `textbox`. So a structural "is this a password input" predicate
13
+ has nothing to read, and the accessible NAME is the only signal present.
14
+
15
+ That is a real ceiling, not a shortcut. This filter is defense-in-depth on one
16
+ enumerated sink; it is not a control that makes snapshotting a credential page
17
+ safe. See the STATED BYPASSES below and property P5 in the plan.
18
+
19
+ MEASURED BEHAVIOUR THIS FILTER IS BUILT AGAINST
20
+ -----------------------------------------------
21
+ * `agent-browser` masks `type=password` itself (renders bullets) and leaks
22
+ the readonly `type=text` credential panel -- the "Token" class, which is
23
+ the one with a recorded in-repo incident.
24
+ * The Playwright MCP leaks both.
25
+ * The no-flag and `-d N` shapes emit the value TWICE: once as the `: value`
26
+ tail and again as a nested `StaticText` child. Redacting only the tail is
27
+ half a fix, so children of a redacted node are suppressed too.
28
+ * `--json` carries the same text inside `data.snapshot`, but `diff snapshot
29
+ --json` carries it under `data.diff`, so the JSON arm recognises a tree by
30
+ SHAPE rather than by field name.
31
+ * `diff snapshot` prefixes a marker column (`+- textbox ...`) and colourises
32
+ the line with SGR escapes, both outside the bullet every regex anchors on.
33
+ * A multi-line value (a textarea holding a PEM block) emits its 2nd..Nth
34
+ lines raw at column 0, so suppression cannot key on indent alone.
35
+ * Playwright's YAML serialiser wraps the WHOLE key in single quotes when the
36
+ accessible name contains ` #`, `: `, `{`, `}`, a backtick or a control
37
+ character (`- 'textbox "API Key #1" [ref=e2]': value`, `''` escaping an
38
+ apostrophe). Every regex below anchors on `- role`, so the quoted key is
39
+ unwrapped before matching and re-quoted on output -- measured against the
40
+ real @playwright/mcp@0.0.78 server during the #7980 review, where a field
41
+ labelled "API Key #1" leaked in clear.
42
+
43
+ STATED BYPASSES (P5's explicit non-coverage -- do not read this filter as
44
+ closing them):
45
+ * a localised or renamed accessible name ("Contrasena", "Clave", "Value");
46
+ * an unnamed node whose role is NOT a text-input role (an unnamed text-input
47
+ node carrying a value IS redacted, on the fail-safe side);
48
+ * a credential rendered outside a text-input role (a status region, a
49
+ validation message, a `<pre>` block);
50
+ * a value split across segmented single-character inputs;
51
+ * every node on a Playwright-MCP registration NOT routed through
52
+ `playwright-mcp-redact-proxy.py` (the sibling transport proxy, #7980), which
53
+ this filter can only reach if a human pipes a saved snapshot through it.
54
+
55
+ FAIL-CLOSED CONTRACT (ADR-095 shape): on refusal, exit 2 with stdout EMPTY and
56
+ a reason on stderr that never quotes the offending input.
57
+ """
58
+
59
+ from __future__ import annotations
60
+
61
+ import json
62
+ import re
63
+ import sys
64
+
65
+ REDACTED = "<redacted>"
66
+
67
+ # CONSUMER CONTRACT (#7980). `playwright-mcp-redact-proxy.py` loads this file by
68
+ # its sibling BASENAME (`REDACTOR_BASENAME` there -- renaming this file is a proxy
69
+ # edit too) with `importlib.util.spec_from_file_location` and binds exactly these
70
+ # four names at startup -- ALL FOUR, so a refactor that renames one fails loud
71
+ # at the proxy's exit 2 instead of as a per-result withhold that reads like an
72
+ # outage. The contract is declared and tested HERE, where it is provided
73
+ # (redact-a11y-snapshot.test.sh carries the import row); the proxy defines no
74
+ # predicate of its own -- this module is the one predicate for both surfaces.
75
+ __all__ = ["redact_text", "looks_like_a11y_tree", "MAX_INPUT_BYTES", "REDACTED"]
76
+
77
+ # 4 MiB. A real snapshot is kilobytes; anything at this size is not a snapshot,
78
+ # and refusing is cheaper than trying to redact it correctly.
79
+ MAX_INPUT_BYTES = 4 * 1024 * 1024
80
+
81
+ # Roles that can carry a user-editable value. A credential does not appear in a
82
+ # `heading` or a `link`, and widening this set widens the over-redaction risk
83
+ # that the must-PASS rows exist to catch.
84
+ TEXT_INPUT_ROLES = frozenset(
85
+ {"textbox", "searchbox", "combobox", "spinbutton", "textarea"}
86
+ )
87
+
88
+ # Descendant roles that repeat a PARENT's value rather than carrying a label
89
+ # of their own. Measured: the no-flag and `-d N` shapes emit the value twice,
90
+ # the second time as a StaticText child. Everything else under a redacted
91
+ # node (an `option` label, say) is a label and must survive.
92
+ VALUE_CARRYING_CHILD_ROLES = frozenset({"StaticText"})
93
+
94
+ # Credential-shaped accessible names. Word-anchored on both sides so
95
+ # "Keyboard shortcut" does not match `key` and "Pinned items" does not match
96
+ # `pin`. Deliberately broader than "password": the only node `agent-browser`
97
+ # leaks is named "Token", so a password-only list would miss the single class
98
+ # with a recorded incident here.
99
+ CREDENTIAL_NAME_RE = re.compile(
100
+ r"\b(?:"
101
+ r"pass(?:word|wd|phrase|code)?"
102
+ r"|token"
103
+ r"|secret"
104
+ r"|credential"
105
+ r"|key"
106
+ r"|bearer"
107
+ r"|otp"
108
+ r"|totp"
109
+ r"|pin"
110
+ r"|2fa"
111
+ r"|mfa"
112
+ r"|two[\s_-]?factor"
113
+ r"|authenticator"
114
+ r"|seed[\s_-]?phrase"
115
+ r"|mnemonic"
116
+ r"|(?:verification|confirmation|one[\s_-]?time|backup|access|recovery"
117
+ r"|security|sms|authenticator|auth(?:entication)?|2fa|mfa|totp)[\s_-]?code"
118
+ r"|connection[\s_-]?string"
119
+ r"|dsn"
120
+ # `signature`, `session` and `cookie` are QUALIFIED, not bare. Bare, they
121
+ # ate `Email signature`, `Session name`, `Cookie name` and
122
+ # `Search sessions` -- measured. A filter that eats ordinary fields gets
123
+ # switched off, which costs more than the narrow miss. The bare words are
124
+ # still caught when they are the WHOLE name, in `_is_credential_name`.
125
+ r"|(?:request|webhook|hmac|jwt|api|payload)[\s_-]?signature"
126
+ r"|authorization"
127
+ r"|session[\s_-]?(?:token|id|key|secret|cookie|string)"
128
+ r"|cookie[\s_-]?(?:value|string|header|jar)"
129
+ r")e?s?\b",
130
+ re.IGNORECASE,
131
+ )
132
+
133
+ def _fmt_name(name: str | None) -> str:
134
+ """Re-emit the name exactly as it arrived, including its absence."""
135
+ return "" if name is None else f' "{name}"'
136
+
137
+
138
+ # Split a camelCase hump, and an acronym that runs INTO a word (`APIKey`), but
139
+ # never an acronym that is already a whole word. The naive
140
+ # `(?<=[a-z0-9])(?=[A-Z])` split `2FA` into `2 FA`, which silently un-matched
141
+ # the `2fa` alternative and leaked a field named `2FA code` -- caught only
142
+ # because the must-REDACT row was driven with the real label.
143
+ _CAMEL_BOUNDARY_RE = re.compile(r"(?<=[a-zA-Z0-9])(?=[A-Z][a-z])|(?<=[a-z])(?=[A-Z]+$)")
144
+ _WORD_SEP_RE = re.compile(r"[_\-]+")
145
+
146
+ # Bare words that are credential-shaped only when they are the ENTIRE accessible
147
+ # name. Qualified forms live in CREDENTIAL_NAME_RE; see the comment there.
148
+ WHOLE_NAME_CREDENTIALS = frozenset({"session", "cookie", "signature"})
149
+
150
+
151
+ def _normalise_name(name: str) -> str:
152
+ """Split camelCase and `_`/`-` runs so one word list matches every casing.
153
+
154
+ Two measured failures, in order of severity:
155
+
156
+ * `_` is a `\\w` character, so `\\btoken\\b` never fired inside
157
+ `SENTRY_AUTH_TOKEN` -- and `API_KEY`, `DB_PASSWORD` and every other
158
+ env-var-style label passed through IN CLEAR. That casing is the standard
159
+ shape of a secrets editor (Doppler, Vercel, Supabase), i.e. exactly the
160
+ credential-panel class this filter exists for. Splitting separators first
161
+ is what fixes it; the alternatives' own `[\\s_-]?` groups still match
162
+ afterwards, because a space satisfies `\\s`.
163
+ * The previous lookbehind form rejected `apiKey` and every English plural
164
+ (`API Keys`, `Tokens`, `Secrets`), which are the literal labels on the
165
+ Cloudflare and Sentry token pages.
166
+ """
167
+ return _CAMEL_BOUNDARY_RE.sub(" ", _WORD_SEP_RE.sub(" ", name))
168
+
169
+ # `- <role> "<name>" [attrs]: <value>` with the value and the attribute bracket
170
+ # both optional. Anchored on the list-dash so prose lines are never rewritten.
171
+ NODE_RE = re.compile(
172
+ r"^(?P<indent>\s*)(?P<bullet>[-+])\s+(?P<role>[A-Za-z][A-Za-z0-9_]*)"
173
+ r'(?:\s+"(?P<name>(?:[^"\\]|\\.)*)")?'
174
+ r"(?P<attrs>(?:\s+\[[^\]]*\])*)"
175
+ r"(?P<sep>:\s*)(?P<value>.*)$"
176
+ )
177
+
178
+ # A bare quoted child, e.g. ` - StaticText "the value"`.
179
+ QUOTED_CHILD_RE = re.compile(
180
+ r"^(?P<indent>\s*)(?P<bullet>[-+])\s+(?P<role>[A-Za-z][A-Za-z0-9_]*)"
181
+ r'\s+"(?P<text>(?:[^"\\]|\\.)*)"(?P<rest>.*)$'
182
+ )
183
+
184
+ INDENT_RE = re.compile(r"^(\s*)")
185
+
186
+ # A YAML single-quoted KEY, e.g. `- 'textbox "Token: prod" [ref=e3]': value`.
187
+ QUOTED_KEY_RE = re.compile(
188
+ r"^(?P<indent>\s*)(?P<bullet>[-+])\s+'(?P<key>(?:[^']|'')*)'(?P<tail>(?::.*)?)$"
189
+ )
190
+
191
+
192
+ def _unquote_key(line: str) -> tuple[str, str | None]:
193
+ """Return (line to MATCH against, the raw quoted key or None).
194
+
195
+ The matched form carries the unescaped key so NODE_RE / QUOTED_CHILD_RE and
196
+ the name predicate see the name Playwright rendered; the raw key is kept so
197
+ a redacted line is re-emitted with the quoting it arrived with.
198
+ """
199
+ quoted = QUOTED_KEY_RE.match(line)
200
+ if not quoted:
201
+ return line, None
202
+ key = quoted.group("key")
203
+ unescaped = key.replace("''", "'")
204
+ return f"{quoted.group('indent')}{quoted.group('bullet')} {unescaped}{quoted.group('tail')}", key
205
+
206
+
207
+ def _render_redacted_node(node: "re.Match[str]", quoted_key: str | None) -> str:
208
+ """Render a credential node with its VALUE replaced, keeping name and quoting."""
209
+ if quoted_key is not None:
210
+ return f"{node.group('indent')}{node.group('bullet')} '{quoted_key}'{node.group('sep')}{REDACTED}"
211
+ return (
212
+ f"{node.group('indent')}{node.group('bullet')} {node.group('role')}"
213
+ f"{_fmt_name(node.group('name'))}{node.group('attrs') or ''}"
214
+ f"{node.group('sep')}{REDACTED}"
215
+ )
216
+
217
+ # Any tree bullet, used to tell a NODE line from a value CONTINUATION line.
218
+ BULLET_RE = re.compile(r"^\s*[-+]\s")
219
+
220
+ # `agent-browser diff snapshot` colourises its output, and SGR escapes sit
221
+ # OUTSIDE the bullet, so every regex below fails on a coloured line. Measured:
222
+ # 8 sentinel survivals straight through the redactor.
223
+ ANSI_SGR_RE = re.compile(r"\x1b\[[0-9;]*m")
224
+
225
+ # A unified-diff marker column. The real CLI emits `+- textbox ...` and
226
+ # `+ - textbox ...`; the suite previously pinned `+ textbox ...`, a shape the
227
+ # CLI never produces, so the rule was verified against a fixture and not
228
+ # against the surface.
229
+ #
230
+ # The lookahead is load-bearing: an ordinary tree line already STARTS with `-`,
231
+ # so a bare `^[+-]` would eat the tree's own bullet. Requiring a SECOND bullet
232
+ # after optional spaces distinguishes a marker column from a bullet.
233
+ DIFF_MARKER_RE = re.compile(r"^(?P<mark>[+-])(?=\s*[-+]\s)")
234
+
235
+
236
+ def _is_credential_name(name: str | None) -> bool:
237
+ """True when the accessible name marks this node as credential-bearing.
238
+
239
+ An UNNAMED node (`name is None`) is not decidable by a name predicate, and
240
+ an unlabeled readonly box is the commonest shape of a generated-credential
241
+ panel. It is handled at the call site as its own case rather than folded in
242
+ here, so the two decisions stay legible.
243
+ """
244
+ if name is None:
245
+ return False
246
+ normalised = _normalise_name(name)
247
+ # A field labelled exactly `Session` / `Cookie` / `Signature` IS the
248
+ # credential; the same word inside a longer label (`Session name`,
249
+ # `Email signature`) is ordinary content. Qualifying them in the pattern
250
+ # loses the first case, so it is recovered here rather than by widening the
251
+ # pattern back to the form that ate four benign fields.
252
+ if normalised.strip().lower() in WHOLE_NAME_CREDENTIALS:
253
+ return True
254
+ return bool(CREDENTIAL_NAME_RE.search(normalised))
255
+
256
+
257
+ def redact_text(text: str) -> str:
258
+ """Redact credential-shaped node values in the indented-text shape."""
259
+ out: list[str] = []
260
+ # Indent of the node currently being suppressed, or None. Children deeper
261
+ # than this inherit the redaction; a line at or above it ends suppression.
262
+ suppress_indent: int | None = None
263
+
264
+ for raw_line in text.split("\n"):
265
+ line = ANSI_SGR_RE.sub("", raw_line)
266
+ marker = ""
267
+ mark = DIFF_MARKER_RE.match(line)
268
+ if mark:
269
+ marker = mark.group("mark")
270
+ line = line[mark.end():]
271
+
272
+ def emit(rendered: str, _marker: str = marker) -> None:
273
+ out.append(_marker + rendered)
274
+
275
+ indent = len(INDENT_RE.match(line).group(1))
276
+
277
+ if suppress_indent is not None and line.strip():
278
+ if BULLET_RE.match(line):
279
+ if indent <= suppress_indent:
280
+ suppress_indent = None
281
+ else:
282
+ # A CONTINUATION line of a multi-line value. A textarea holding
283
+ # a PEM block or an SSH key emits its 2nd..Nth lines raw, at
284
+ # column 0 -- so the old `indent <= suppress_indent` test ended
285
+ # suppression on the second line and printed the rest of the key
286
+ # in clear, along with every StaticText duplicate below it.
287
+ # Measured on the real CLI, on all four output shapes.
288
+ #
289
+ # It is not a node, so it must not end suppression; it carries
290
+ # the tail of the secret, so it must not be emitted. The node
291
+ # line above already rendered `<redacted>` in its place.
292
+ continue
293
+
294
+ match_line, quoted_key = _unquote_key(line)
295
+ node = NODE_RE.match(match_line)
296
+ # An UNNAMED text-input node carrying a value is redacted on the
297
+ # fail-safe side. We cannot decide it by name -- there is no name -- and
298
+ # an unlabeled readonly box is the commonest shape of a
299
+ # generated-credential panel. Playwright derives an accessible name from
300
+ # a label, placeholder or aria-label, so a genuinely unnamed input with
301
+ # a value is rare; losing its value costs an agent little, and keeping
302
+ # it is the class with a recorded in-repo incident.
303
+ unnamed_input = (
304
+ node is not None
305
+ and node.group("name") is None
306
+ and node.group("role") in TEXT_INPUT_ROLES
307
+ and node.group("value").strip() != ""
308
+ )
309
+ if node and node.group("role") in TEXT_INPUT_ROLES and (
310
+ unnamed_input or _is_credential_name(node.group("name"))
311
+ ):
312
+ emit(_render_redacted_node(node, quoted_key))
313
+ suppress_indent = indent
314
+ continue
315
+
316
+ if suppress_indent is not None and indent > suppress_indent:
317
+ # A descendant of a redacted node. Two distinct cases, and the
318
+ # earlier revision got both wrong because QUOTED_CHILD_RE strictly
319
+ # SUBSUMES NODE_RE -- it matched first, so a nested credential node
320
+ # had its NAME redacted and its VALUE preserved. That is the exact
321
+ # inversion of the point: it destroyed the signal and kept the
322
+ # secret.
323
+ inner = NODE_RE.match(match_line)
324
+ if inner:
325
+ # A node with its own `: value` tail -- redact the VALUE, keep
326
+ # the name, exactly as for the parent.
327
+ emit(_render_redacted_node(inner, quoted_key))
328
+ continue
329
+ child = QUOTED_CHILD_RE.match(match_line)
330
+ if child and child.group("role") in VALUE_CARRYING_CHILD_ROLES:
331
+ # The measured `-d N` / no-flag duplicate: the value repeated as
332
+ # a StaticText child. Redact it.
333
+ emit(
334
+ f"{child.group('indent')}{child.group('bullet')} {child.group('role')} "
335
+ f"\"{REDACTED}\"{child.group('rest')}"
336
+ )
337
+ continue
338
+ # Anything else under a redacted node is a LABEL, not a value --
339
+ # `option "id"`, `option "email"` under a combobox named
340
+ # "Primary key". Redacting those destroys the agent's ability to
341
+ # pick the right option while protecting nothing, so they pass
342
+ # through untouched.
343
+
344
+ emit(line)
345
+
346
+ return "\n".join(out)
347
+
348
+
349
+ def looks_like_a11y_tree(value: str) -> bool:
350
+ """True when a JSON string value carries an accessibility tree.
351
+
352
+ Keying on the field NAME was the defect: `snapshot --json` puts the tree
353
+ under `data.snapshot`, but `diff snapshot --json` puts it under `data.diff`,
354
+ so the envelope parsed cleanly, matched no key, and every value was emitted
355
+ verbatim at exit 0 -- on a command the interceptor ALLOWS, because the
356
+ redactor is in the pipe. A key allowlist is a standing bet that the CLI
357
+ never adds a fourth key; recognising the SHAPE does not take that bet.
358
+ """
359
+ for raw in value.split("\n"):
360
+ line = ANSI_SGR_RE.sub("", raw)
361
+ mark = DIFF_MARKER_RE.match(line)
362
+ if mark:
363
+ line = line[mark.end():]
364
+ line, _quoted = _unquote_key(line)
365
+ if NODE_RE.match(line) or QUOTED_CHILD_RE.match(line):
366
+ return True
367
+ return False
368
+
369
+
370
+ def _redact_json_in_place(node: object) -> object:
371
+ """Redact any string field carrying an a11y tree, at any depth."""
372
+ if isinstance(node, dict):
373
+ return {
374
+ k: (redact_text(v)
375
+ if isinstance(v, str) and (k == "snapshot" or looks_like_a11y_tree(v))
376
+ else _redact_json_in_place(v))
377
+ for k, v in node.items()
378
+ }
379
+ if isinstance(node, list):
380
+ return [_redact_json_in_place(v) for v in node]
381
+ return node
382
+
383
+
384
+ def die(reason: str) -> None:
385
+ """Fail closed. Never quote the input -- that would re-open the leak."""
386
+ sys.stderr.write(f"redact-a11y-snapshot: refusing to emit: {reason}\n")
387
+ sys.exit(2)
388
+
389
+
390
+ def main() -> None:
391
+ raw = sys.stdin.buffer.read(MAX_INPUT_BYTES + 1)
392
+ if len(raw) > MAX_INPUT_BYTES:
393
+ die(f"input exceeds {MAX_INPUT_BYTES} bytes")
394
+
395
+ try:
396
+ text = raw.decode("utf-8")
397
+ except UnicodeDecodeError:
398
+ die("input is not valid UTF-8")
399
+
400
+ if not text:
401
+ return
402
+
403
+ # Locate a JSON payload even when something is printed AHEAD of it.
404
+ #
405
+ # This is the shape the guard itself prescribes: `agent-browser snapshot -i
406
+ # --json 2>&1 | python3 <this>`. The `2>&1` merges any agent-browser
407
+ # diagnostic in front of the JSON, so a `startswith` test is False, the
408
+ # input falls to the line-based path, NODE_RE never matches a single-line
409
+ # JSON blob, and the credential passes through verbatim at exit 0.
410
+ # Measured, and it is the highest-severity shape because our own
411
+ # instructions steer every agent onto it.
412
+ brace = min(
413
+ (i for i in (text.find("{"), text.find("[")) if i != -1),
414
+ default=-1,
415
+ )
416
+ if brace != -1:
417
+ try:
418
+ parsed = json.loads(text[brace:])
419
+ except json.JSONDecodeError as exc:
420
+ # Fail closed on anything that PRESENTS as a JSON document: some
421
+ # line, after stripping, begins with `{` or `[`.
422
+ #
423
+ # The earlier form keyed on the literal `"snapshot"` being present,
424
+ # so an envelope truncated BEFORE that key -- or one with a typo'd
425
+ # key -- matched neither clause, fell through to the line-based
426
+ # path, and was emitted verbatim at exit 0. A partial envelope is
427
+ # exactly what a killed `agent-browser` produces, so that was the
428
+ # likely shape, not an exotic one.
429
+ #
430
+ # A stray brace INSIDE an a11y node value does not begin a line, so
431
+ # ordinary text is unaffected and does not take the run down.
432
+ if any(ln.lstrip().startswith(("{", "[")) for ln in text.splitlines()):
433
+ die(f"input looks like JSON but does not parse ({exc.msg})")
434
+ else:
435
+ prefix = redact_text(text[:brace])
436
+ sys.stdout.write(prefix + json.dumps(_redact_json_in_place(parsed)))
437
+ return
438
+
439
+ sys.stdout.write(redact_text(text))
440
+
441
+
442
+ if __name__ == "__main__":
443
+ main()
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env python3
2
+ """Capture Playwright-MCP stdio fixtures from the surface (#7980, Phase 0.2).
3
+
4
+ python3 capture-playwright-mcp-fixtures.py <output-dir> -- <server argv...>
5
+
6
+ Serves a synthesized form on 127.0.0.1 (no real credential, no real origin),
7
+ drives the given MCP server over its own stdin/stdout with hand-written
8
+ JSON-RPC, and writes ONE JSON file per captured message into <output-dir>:
9
+
10
+ initialize.json tools-list.json roots-list-request.json
11
+ navigate.json snapshot.json snapshot-filename.json
12
+ snapshot-meta-json.json snapshot-meta-raw.json find.json
13
+ evaluate.json screenshot.json close.json
14
+ raw-stdout.bin framing.json page.html
15
+
16
+ The page puts the sentinel `ZZQP-SENTINEL-7980` ONLY in credential-named inputs
17
+ (password, Token) and `ZZQP-BENIGN-7980` in Notes, so a redaction assertion can
18
+ count both halves. Every `@playwright/mcp` bump re-runs this driver so the suite
19
+ tests captures from the pinned surface, never from the author (ADR-213 round 3).
20
+
21
+ Framing assertion (row 12): every server stdout message is one `\n`-terminated
22
+ line that parses as a JSON object, no embedded newline, no `Content-Length`.
23
+
24
+ stdlib only. Exit 0 on a complete capture, 1 on a framing violation, 2 on usage.
25
+ """
26
+ from __future__ import annotations
27
+
28
+ import contextlib
29
+ import http.server
30
+ import json
31
+ import os
32
+ import selectors
33
+ import subprocess
34
+ import sys
35
+ import threading
36
+ import time
37
+
38
+ PAGE_HTML = """<!doctype html>
39
+ <html><head><meta charset="utf-8"><title>probe 7980</title></head>
40
+ <body>
41
+ <form>
42
+ <label>Enter your password <input type="password" value="ZZQP-SENTINEL-7980"></label>
43
+ <label>Token <input type="text" readonly value="ZZQP-SENTINEL-7980"></label>
44
+ <label>Email address <input type="email" value="probe-user@example.invalid"></label>
45
+ <label>Notes <textarea>ZZQP-BENIGN-7980</textarea></label>
46
+ <button type="button">Go</button>
47
+ </form>
48
+ </body></html>
49
+ """
50
+
51
+
52
+ class _Quiet(http.server.SimpleHTTPRequestHandler):
53
+ def log_message(self, *_args): # noqa: D401 - silence the server
54
+ pass
55
+
56
+ def do_GET(self): # noqa: N802 - http.server API
57
+ body = PAGE_HTML.encode()
58
+ self.send_response(200)
59
+ self.send_header("Content-Type", "text/html; charset=utf-8")
60
+ self.send_header("Content-Length", str(len(body)))
61
+ self.end_headers()
62
+ self.wfile.write(body)
63
+
64
+
65
+ def serve_page():
66
+ srv = http.server.ThreadingHTTPServer(("127.0.0.1", 0), _Quiet)
67
+ threading.Thread(target=srv.serve_forever, daemon=True).start()
68
+ return srv, f"http://127.0.0.1:{srv.server_address[1]}/page.html"
69
+
70
+
71
+ class Driver:
72
+ def __init__(self, argv, out):
73
+ self.out = out
74
+ self.child = subprocess.Popen(
75
+ argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stderr, bufsize=0
76
+ )
77
+ self.sel = selectors.DefaultSelector()
78
+ self.sel.register(self.child.stdout, selectors.EVENT_READ)
79
+ self.buf = bytearray()
80
+ self.raw = bytearray()
81
+ self.next_id = 1
82
+ self.violations = []
83
+
84
+ def send(self, obj):
85
+ line = json.dumps(obj, separators=(",", ":")).encode() + b"\n"
86
+ self.child.stdin.write(line)
87
+ self.child.stdin.flush()
88
+
89
+ def request(self, method, params=None):
90
+ rid = self.next_id
91
+ self.next_id += 1
92
+ msg = {"jsonrpc": "2.0", "id": rid, "method": method}
93
+ if params is not None:
94
+ msg["params"] = params
95
+ self.send(msg)
96
+ return rid
97
+
98
+ def read_line(self, timeout=60.0):
99
+ deadline = time.monotonic() + timeout
100
+ while b"\n" not in self.buf:
101
+ remaining = deadline - time.monotonic()
102
+ if remaining <= 0:
103
+ raise TimeoutError("no line from server within timeout")
104
+ if not self.sel.select(timeout=remaining):
105
+ continue
106
+ chunk = os.read(self.child.stdout.fileno(), 65536)
107
+ if not chunk:
108
+ raise EOFError("server closed stdout")
109
+ self.buf += chunk
110
+ self.raw += chunk
111
+ line, _, rest = bytes(self.buf).partition(b"\n")
112
+ self.buf = bytearray(rest)
113
+ return line
114
+
115
+ def wait_response(self, rid, name):
116
+ """Read until the response for `rid` arrives; capture server requests on the way."""
117
+ while True:
118
+ line = self.read_line()
119
+ if line.startswith(b"Content-Length"):
120
+ self.violations.append("Content-Length header on stdout")
121
+ try:
122
+ obj = json.loads(line.decode("utf-8", errors="replace"))
123
+ except json.JSONDecodeError:
124
+ self.violations.append(f"non-JSON stdout line ({len(line)} bytes)")
125
+ continue
126
+ if not isinstance(obj, dict):
127
+ self.violations.append("stdout line is not a JSON object")
128
+ continue
129
+ if "method" in obj and "id" in obj:
130
+ # server -> client request (roots/list); answer it and record it.
131
+ self.save("roots-list-request" if obj["method"] == "roots/list" else f"server-request-{obj['method'].replace('/', '-')}", obj)
132
+ self.send({"jsonrpc": "2.0", "id": obj["id"], "result": {"roots": []}})
133
+ continue
134
+ if "method" in obj:
135
+ self.save(f"notification-{obj['method'].replace('/', '-')}", obj)
136
+ continue
137
+ if obj.get("id") == rid:
138
+ self.save(name, obj)
139
+ return obj
140
+ self.save(f"unexpected-{obj.get('id')}", obj)
141
+
142
+ def save(self, name, obj):
143
+ path = os.path.join(self.out, f"{name}.json")
144
+ with open(path, "w", encoding="utf-8") as fh:
145
+ json.dump(obj, fh, indent=2, ensure_ascii=False)
146
+ fh.write("\n")
147
+
148
+ def call(self, name, tool, arguments=None):
149
+ rid = self.request("tools/call", {"name": tool, "arguments": arguments or {}})
150
+ return self.wait_response(rid, name)
151
+
152
+ def finish(self):
153
+ with contextlib.suppress(OSError):
154
+ self.child.stdin.close()
155
+ try:
156
+ self.child.wait(timeout=30)
157
+ except subprocess.TimeoutExpired:
158
+ self.child.kill()
159
+ with open(os.path.join(self.out, "raw-stdout.bin"), "wb") as fh:
160
+ fh.write(bytes(self.raw))
161
+ lines = bytes(self.raw).split(b"\n")
162
+ trailing = lines[-1]
163
+ if trailing:
164
+ self.violations.append("stdout did not end with a newline")
165
+ framing = {
166
+ "messages": len(lines) - 1,
167
+ "content_length_header": any(l.startswith(b"Content-Length") for l in lines),
168
+ "every_line_is_json_object": all(
169
+ isinstance(json.loads(l.decode("utf-8", errors="replace")), dict) for l in lines[:-1]
170
+ ),
171
+ "violations": self.violations,
172
+ }
173
+ self.save("framing", framing)
174
+ return framing
175
+
176
+
177
+ def main(argv):
178
+ if "--" not in argv or argv.index("--") != 1 or len(argv) < 3:
179
+ sys.stderr.write(__doc__)
180
+ return 2
181
+ out = argv[0]
182
+ server_argv = argv[2:]
183
+ os.makedirs(out, exist_ok=True)
184
+ with open(os.path.join(out, "page.html"), "w", encoding="utf-8") as fh:
185
+ fh.write(PAGE_HTML)
186
+ srv, url = serve_page()
187
+ try:
188
+ d = Driver(server_argv, out)
189
+ rid = d.request(
190
+ "initialize",
191
+ {
192
+ "protocolVersion": "2025-06-18",
193
+ "capabilities": {"roots": {"listChanged": True}},
194
+ "clientInfo": {"name": "capture-playwright-mcp-fixtures", "version": "7980"},
195
+ },
196
+ )
197
+ d.wait_response(rid, "initialize")
198
+ d.send({"jsonrpc": "2.0", "method": "notifications/initialized"})
199
+ d.wait_response(d.request("tools/list"), "tools-list")
200
+ d.call("navigate", "browser_navigate", {"url": url})
201
+ d.call("snapshot", "browser_snapshot")
202
+ d.call("snapshot-filename", "browser_snapshot", {"filename": "explicit-snap.yml"})
203
+ d.call("snapshot-meta-json", "browser_snapshot", {"_meta": {"json": True}})
204
+ d.call("snapshot-meta-raw", "browser_snapshot", {"_meta": {"raw": True}})
205
+ d.call("find", "browser_find", {"text": "Token"})
206
+ d.call("evaluate", "browser_evaluate", {"function": "() => ({a: 1, b: [1,2]})"})
207
+ d.call("screenshot", "browser_take_screenshot", {"type": "png"})
208
+ d.call("close", "browser_close")
209
+ framing = d.finish()
210
+ finally:
211
+ srv.shutdown()
212
+ print(json.dumps(framing))
213
+ return 1 if framing["violations"] else 0
214
+
215
+
216
+ if __name__ == "__main__":
217
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env python3
2
+ """Known-NEGATIVE relay for the proxy suite (#7980, QG5): spawn the server,
3
+ pump bytes both ways, rewrite nothing. Every redaction/withhold/refuse row must
4
+ be RED against this file and every must-PASS row GREEN; it is the pre-fix
5
+ artefact, never shipped."""
6
+ import os, selectors, subprocess, sys # noqa: E401
7
+
8
+ child = subprocess.Popen(sys.argv[sys.argv.index("--") + 1:], stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=0, start_new_session=True)
9
+ sys.stderr.write(f"fake-passthrough-proxy: child pgid {os.getpgid(child.pid)}\n"); sys.stderr.flush()
10
+ sel = selectors.DefaultSelector()
11
+ sel.register(sys.stdin.buffer, selectors.EVENT_READ, "in")
12
+ sel.register(child.stdout, selectors.EVENT_READ, "out")
13
+ while sel.get_map():
14
+ for key, _ in sel.select():
15
+ data = os.read(key.fileobj.fileno(), 65536)
16
+ if key.data == "in":
17
+ if not data:
18
+ sel.unregister(key.fileobj); child.stdin.close(); continue
19
+ child.stdin.write(data); child.stdin.flush()
20
+ else:
21
+ if not data:
22
+ sel.unregister(key.fileobj); continue
23
+ sys.stdout.buffer.write(data); sys.stdout.buffer.flush()
24
+ sys.exit(child.wait())