@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,556 @@
1
+ #!/usr/bin/env python3
2
+ """Inventory and shrink-only ratchet for signal helpers inside shell test suites.
3
+
4
+ WHY THIS EXISTS
5
+ ---------------
6
+ A helper that walks `$PPID` upwards and signals the outermost ancestor whose argv matches is bounded
7
+ only by its own predicate. Mutate the predicate (invert it, drop it, make it a catch-all) and every
8
+ ancestor matches: the walk reaches the top of the user's desktop session. That happened four times on
9
+ 2026-10-09 (the learning recorded that day under the learnings test-failures category: "an inverted-match
10
+ mutant of an ancestor-walking helper ended the desktop session four times"). This scan lists the suites that
11
+ contain such a helper, and the other signal-to-ancestors patterns, BEFORE anyone mutates them, and
12
+ fails the full battery when a new one lands unbaselined or an unbounded walker is baselined.
13
+
14
+ USAGE
15
+ -----
16
+ scan-ancestor-signal-helpers.py [--root DIR] [--baseline FILE] [--list] [--write-baseline FILE] [PATH ...]
17
+
18
+ * Population: the tracked files matching the pathspecs in PATHSPECS (`*.test.sh`, `test-*.sh`,
19
+ `test_*.sh` and the mutation-run names `*-mutation-battery.sh`, `*.mutation.sh`, `*-mutations.sh`),
20
+ read from ONE git listing (NUL separated) made with every GIT_* variable removed from the child
21
+ environment, or the explicit PATHs given (paths are used as given and shown as given).
22
+ * Without --baseline the scan is list-only: rc 0 and the notice `no baseline: listing only`, so a
23
+ plugin consumer running it on their own repository does not see every site as new.
24
+ * With --baseline the verdict is gated on classes W, P and G (below). Exit 0 clean, 1 findings,
25
+ 3 UNRESOLVED (empty population, failed git, unreadable or malformed baseline, a listed member that
26
+ is missing or was skipped (symlink, special file, over 2 MB: an unread file is an unchecked file), or
27
+ any uncaught Exception or KeyboardInterrupt: a traceback from those can never read as rc 1 "findings").
28
+ A BaseException subclass outside those (GeneratorExit, CancelledError) is unreachable from this synchronous,
29
+ stdlib-only scan and is deliberately not caught: it would exit 1 with a traceback. A usage error is argparse's rc 2.
30
+ * --list prints `class TAB bounded TAB path TAB text` for every finding of every class (bounded is
31
+ yes or no for W and a dash for the others); `--list PATH...` scopes it to the given files, which is
32
+ how a mutation seat checks the one file it is about to mutate.
33
+ * --write-baseline FILE writes the gated rows of the tracked population (overwrites the whole file:
34
+ review the diff). It refuses (rc 2) with PATHs or --list, refuses while any W is unbounded, and refuses
35
+ (rc 3) while any member was skipped.
36
+ * In explicit-PATH mode only baseline rows whose path is among the given PATHs are judged stale.
37
+
38
+ CLASSES (a finding is one source line, content-keyed)
39
+ -----------------------------------------------------
40
+ W (gated) ancestor walk with a signal: a self-referential cursor assignment (v=$(... /proc/$v/stat
41
+ ...), v=$(ps -o ppid= -p $v), v=$(... $v ... PPid ...)) with kill, pkill or killall within
42
+ 40 lines either side (raw text, so heredoc and string-embedded helpers count). Reported
43
+ bounded=yes only when a NON-COMMENT line from 15 lines above to 3 lines below the cursor
44
+ line mentions SOLEUR_TEST_SUITE_PID in a comparison (!=, ==, =, -ne, -eq, -lt, -le, -gt, -ge)
45
+ together with exit, break or return on that line, or in a while/until loop condition. A
46
+ mention only in a comment, an echo or a printf, or a presence, emptiness or numeric-validation
47
+ test ([ -n ], [ -z ], =~), reads bounded=no. bounded=yes is a LEXICAL
48
+ check: it cannot see that an unset variable means "signal nothing" or that a trailing
49
+ `|| true` defeats the comparison.
50
+ P (gated) a signal to the parent: kill and $PPID (or ps -o ppid=) on one line, or a variable assigned
51
+ from $PPID / ps -o ppid= within 20 lines above a kill that names it.
52
+ G (gated) an all-process or own-group signal at command position: kill [-SIG] 0 and kill [-SIG] -1.
53
+ A line over 4 KB that contains a signal verb is reported here too (fail closed).
54
+ L (listed) targeted group signals (kill -- -<pgid>) and name-pattern signals (pkill, killall). Never
55
+ gated, no baseline: they are not signals to ancestors.
56
+ Never findings: comment lines, signal verbs inside quoted spans (except the body of sh -c, bash -c,
57
+ eval and trap strings, which are scanned as code), kill -0, kill -l. A verb may carry an absolute path
58
+ and the usual prefixes (sudo, env, VAR=x, time, nice, setsid, timeout with options).
59
+
60
+ READING MODEL
61
+ -------------
62
+ Files are decoded with errors="surrogateescape" and split on "\\n" only (never str.splitlines(), which
63
+ splits on separators bash does not), with "\\r" stripped. A line over 4 KB gets no regex work (counted as
64
+ overlong; a substring pre-filter still reports a signal verb on it), a file over 2 MB, a symlink or a
65
+ special file is counted skipped. Only the Python standard library is used and nothing from the scanned
66
+ tree is imported or executed: the scan reads text and sends no signal.
67
+
68
+ BASELINE ROWS
69
+ -------------
70
+ `<path> TAB <class> TAB <normalised line>` (whitespace collapsed, a trailing comment cut), matched as a
71
+ multiset against the live gated findings. New, stale and unbounded are red; a baselined W that reads
72
+ bounded=no is red (an unbounded walker cannot be baselined).
73
+
74
+ DOCUMENTED BLIND SPOTS
75
+ ----------------------
76
+ Multi-line quoted strings and backslash-newline continuations (kill \\ then -1); a walk written in
77
+ another language (os.getppid, os.kill) or through read, printf -v, pgrep -P, a function or $PROC_ROOT; a
78
+ two-step cursor (parent=$(...); cur=$parent); a kill more than 40 lines from the cursor, a cursor line
79
+ over 4 KB, or a kill reached through a function, a variable verb ($K), kill $(...) or xargs kill; a
80
+ parent held in a variable made by read, printf -v or let, or more than 20 lines above its kill; helpers
81
+ sourced from a non-suite file; scripts that match none of the name shapes (a helper in a lib or a hook);
82
+ fixtures stored under another extension; signal-delivering programs other than kill, pkill and killall
83
+ (systemctl --user, loginctl, tmux kill-server, fuser -k, docker kill, killall5). The scan is a finding
84
+ aid plus a ratchet on the lines it can see, not a proof of absence, and class L is listed but never
85
+ gated. The producer lists tracked files only: an untracked suite is not scanned until it is added.
86
+ """
87
+
88
+ import argparse
89
+ import bisect
90
+ import collections
91
+ import contextlib
92
+ import os
93
+ import re
94
+ import stat
95
+ import subprocess
96
+ import sys
97
+
98
+ TOKEN = "SOLEUR_TEST_SUITE_PID"
99
+ KILL_WINDOW = 40 # a signal within this many lines of a W cursor
100
+ BOUND_ABOVE = 15 # bound token window above the cursor line
101
+ BOUND_BELOW = 3 # bound token window below the cursor line
102
+ DERIVED_WINDOW = 20 # parent variable assigned within this many lines above its kill
103
+ MAX_LINE = 4096
104
+ MAX_FILE = 2 * 1024 * 1024
105
+ GATED = ("W", "P", "G")
106
+ PATHSPECS = [
107
+ "*.test.sh", ":(glob)**/test-*.sh", ":(glob)**/test_*.sh",
108
+ ":(glob)**/*-mutation-battery.sh", ":(glob)**/*.mutation.sh", ":(glob)**/*-mutations.sh",
109
+ ]
110
+
111
+ # A signal verb at command position (the text is quote-masked first).
112
+ CMDPOS = re.compile(
113
+ r"(?:^|[;&|(){`!]|\$\(|\b(?:then|do|else|if|elif|while|until)\b)\s*"
114
+ r"(?:(?:\w+=\S*|sudo|exec|command|builtin|nohup|time|nice|setsid|env)\s+(?:-\S+\s+)*"
115
+ r"|timeout\s+(?:[-\dA-Z][^\s=]*\s+){1,4}|\\)*"
116
+ r"(?:[\w.+~/-]*/)?(kill|pkill|killall)(?![\w./-])"
117
+ )
118
+ # A -c / eval / trap body: a quoted span that runs as shell text and is masked in the outer line.
119
+ BODY = re.compile(r"(?:\b(?:sh|bash|dash|zsh)\s+-\w*c\w*|\beval|\btrap)\s+(['\"])(.*?)\1")
120
+ # A signal word anywhere in raw code (used only for the W window; string-embedded helpers count).
121
+ LOOSE_SIGNAL = re.compile(r"(?<![\w.-])(?:kill|pkill|killall)(?![\w./-])(?:\s+(?!-0\b|-l\b|-L\b|-s\s+0\b)|$)")
122
+ CURSOR = re.compile(r"(?:^|[\s;&|({])(?:local\s+|export\s+|declare\s+-\w+\s+)?(\w+)=(?:\"?\$\(|`)")
123
+ PPID_ASSIGN = re.compile(
124
+ r"(?:^|[\s;&|({])(?:local\s+|export\s+|readonly\s+|declare\s+-\w+\s+)?(\w+)=(?:\"?\$\{?PPID\b|\"?\$\(.{0,200}?\b(?i:ppid)=|`[^`]{0,200}\b(?i:ppid)=)"
125
+ )
126
+ PPID_USE = re.compile(r"\$\{?PPID\b|\bps\b[^;|&)]*\b(?i:ppid)=")
127
+ TARGET_VAR = re.compile(r"^\$\{?(\w+)\}?$")
128
+ CMP = re.compile(r"(?:^|\s)(?:!=|==|=|-ne|-eq|-lt|-le|-gt|-ge)(?:\s|$)")
129
+ EXIT_WORD = re.compile(r"\b(?:exit|break|return)\b")
130
+ LOOP_WORD = re.compile(r"\b(?:while|until)\b")
131
+ # Only lines that carry one of these can matter to a detector or a window: the rest are never analysed.
132
+ KEYS = ("kill", "PPID", "ppid", "PPid", "/proc/", TOKEN)
133
+ NOT_A_BOUND = re.compile(r"^\s*(?:echo|printf|print|cat|:)\b")
134
+
135
+
136
+ class Unresolved(Exception):
137
+ """The scan could not produce a verdict (rc 3)."""
138
+
139
+
140
+ Finding = collections.namedtuple("Finding", "path cls text bounded lineno")
141
+
142
+
143
+ def normalise(text):
144
+ return " ".join(text.split())
145
+
146
+
147
+ def analyse(line):
148
+ """Return (code, masked): code is the line cut at an unquoted comment start; masked is code with the
149
+ contents of quoted spans blanked (same length, so indexes map between the two)."""
150
+ code = []
151
+ masked = []
152
+ quote = None
153
+ i = 0
154
+ n = len(line)
155
+ while i < n:
156
+ c = line[i]
157
+ if quote is None:
158
+ if c == "\\" and i + 1 < n:
159
+ code.append(line[i:i + 2])
160
+ masked.append(line[i:i + 2])
161
+ i += 2
162
+ continue
163
+ if c == "#" and (i == 0 or line[i - 1].isspace() or line[i - 1] in ";&|"):
164
+ break
165
+ if c == "'" or c == '"':
166
+ quote = c
167
+ code.append(c)
168
+ masked.append(c)
169
+ else:
170
+ if quote == '"' and c == "\\" and i + 1 < n:
171
+ code.append(line[i:i + 2])
172
+ masked.append(" ")
173
+ i += 2
174
+ continue
175
+ if c == quote:
176
+ quote = None
177
+ code.append(c)
178
+ masked.append(c)
179
+ else:
180
+ code.append(c)
181
+ masked.append(" ")
182
+ i += 1
183
+ return "".join(code), "".join(masked)
184
+
185
+
186
+ def arg_tokens(code, masked, start):
187
+ """The tokens after a verb, cut at the next unquoted terminator or redirection."""
188
+ end = len(masked)
189
+ for j in range(start, len(masked)):
190
+ if masked[j] in ";&|)}`<>":
191
+ end = j
192
+ break
193
+ toks = []
194
+ for raw in code[start:end].split():
195
+ toks.append(raw.strip("'\""))
196
+ return toks
197
+
198
+
199
+ def classify_kill(toks, is_derived):
200
+ """The class of one kill invocation, or None (a probe, a listing, or a plain pid). is_derived(var) says
201
+ whether var was assigned from the parent pid within DERIVED_WINDOW lines above this kill."""
202
+ if not toks:
203
+ return None
204
+ first = toks[0]
205
+ i = 0
206
+ if first in ("-l", "-L", "--list", "--table"):
207
+ return None
208
+ if first in ("-s", "-n", "--signal"):
209
+ if len(toks) < 2:
210
+ return None
211
+ if toks[1] == "0":
212
+ return None
213
+ i = 2
214
+ elif first == "-0":
215
+ return None
216
+ elif first.startswith("-") and first != "--":
217
+ i = 1
218
+ if i < len(toks) and toks[i] == "--":
219
+ i += 1
220
+ targets = toks[i:]
221
+ if PPID_USE.search(" ".join(toks)):
222
+ return "P"
223
+ kind = None
224
+ for t in targets:
225
+ if t in ("0", "-1"):
226
+ return "G"
227
+ m = TARGET_VAR.match(t) or (TARGET_VAR.match(t[1:]) if t.startswith("-") else None)
228
+ if m and is_derived(m.group(1)):
229
+ return "P"
230
+ if t.startswith("-") and kind is None:
231
+ kind = "L"
232
+ return kind
233
+
234
+
235
+ def derived_at(assigns, var, i):
236
+ idxs = assigns.get(var)
237
+ if not idxs:
238
+ return False
239
+ k = bisect.bisect_left(idxs, i - DERIVED_WINDOW)
240
+ return k < len(idxs) and idxs[k] <= i
241
+
242
+
243
+ def is_bound_line(code):
244
+ if TOKEN not in code or NOT_A_BOUND.match(code):
245
+ return False
246
+ if not CMP.search(code):
247
+ return False
248
+ return bool(EXIT_WORD.search(code) or LOOP_WORD.search(code))
249
+
250
+
251
+ def scan_text(path, text, counters):
252
+ lines = [ln.rstrip("\r") for ln in text.split("\n")]
253
+ counters["overlong"] += sum(1 for ln in lines if len(ln) > MAX_LINE)
254
+ findings = []
255
+ if "kill" not in text:
256
+ return findings
257
+ n = len(lines)
258
+ code = [""] * n
259
+ masked = [""] * n
260
+ for i, ln in enumerate(lines):
261
+ if len(ln) > MAX_LINE:
262
+ if LOOSE_SIGNAL.search(ln):
263
+ head = normalise(ln[:200])[:100]
264
+ findings.append(Finding(path, "G", "<overlong line, %d chars, carries a signal verb> %s" % (len(ln), head), "-", i + 1))
265
+ continue
266
+ if not any(k in ln for k in KEYS):
267
+ continue
268
+ if ln.lstrip().startswith("#"):
269
+ continue
270
+ code[i], masked[i] = analyse(ln)
271
+
272
+ assigns = collections.defaultdict(list)
273
+ for i in range(n):
274
+ if "PPID" in code[i] or "ppid=" in code[i].lower():
275
+ for m in PPID_ASSIGN.finditer(code[i]):
276
+ assigns[m.group(1)].append(i)
277
+
278
+ for i in range(n):
279
+ if not code[i]:
280
+ continue
281
+ # signal verbs at command position
282
+ for m in CMDPOS.finditer(masked[i]):
283
+ verb = m.group(1)
284
+ toks = arg_tokens(code[i], masked[i], m.end())
285
+ if verb in ("pkill", "killall"):
286
+ cls = "L"
287
+ else:
288
+ cls = classify_kill(toks, lambda v, i=i: derived_at(assigns, v, i))
289
+ if cls:
290
+ findings.append(Finding(path, cls, normalise(code[i]), "-", i + 1))
291
+ # the same detectors over the body of sh -c '...', eval "..." and trap '...' (masked in the outer line)
292
+ for bm in BODY.finditer(code[i]):
293
+ bcode, bmasked = analyse(bm.group(2))
294
+ for m in CMDPOS.finditer(bmasked):
295
+ verb = m.group(1)
296
+ toks = arg_tokens(bcode, bmasked, m.end())
297
+ if verb in ("pkill", "killall"):
298
+ cls = "L"
299
+ else:
300
+ cls = classify_kill(toks, lambda v, i=i: derived_at(assigns, v, i))
301
+ if cls:
302
+ findings.append(Finding(path, cls, normalise(code[i]), "-", i + 1))
303
+ # W cursor: a self-referential assignment, with a signal nearby
304
+ if ("/proc/" in code[i] or "ppid" in code[i].lower()) and ("=$(" in code[i] or '="$(' in code[i] or "=`" in code[i]):
305
+ for m in CURSOR.finditer(code[i]):
306
+ v = m.group(1)
307
+ tail = code[i][m.end():]
308
+ ref = re.compile(r"\$\{?%s\b" % re.escape(v))
309
+ form1 = re.search(r"/proc/\$\{?%s\}?/(?:stat|status)" % re.escape(v), tail)
310
+ form2 = re.search(r"\bps\b", tail) and re.search(r"ppid", tail) and ref.search(tail)
311
+ form3 = "PPid" in tail and ref.search(tail)
312
+ if not (form1 or form2 or form3):
313
+ continue
314
+ lo = max(0, i - KILL_WINDOW)
315
+ hi = min(n, i + KILL_WINDOW + 1)
316
+ if not any(code[j] and LOOSE_SIGNAL.search(code[j]) for j in range(lo, hi)):
317
+ continue
318
+ blo = max(0, i - BOUND_ABOVE)
319
+ bhi = min(n, i + BOUND_BELOW + 1)
320
+ bounded = "yes" if any(is_bound_line(code[j]) for j in range(blo, bhi)) else "no"
321
+ findings.append(Finding(path, "W", normalise(code[i]), bounded, i + 1))
322
+ break
323
+ findings.sort(key=lambda f: (f.lineno, f.cls))
324
+ return findings
325
+
326
+
327
+ def git_population(root):
328
+ env = {k: v for k, v in os.environ.items() if not k.startswith("GIT_")}
329
+ cmd = ["git", "-C", root, "ls-files", "-z", "--"] + PATHSPECS
330
+ try:
331
+ cp = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=120)
332
+ except (OSError, subprocess.SubprocessError) as exc:
333
+ raise Unresolved("git listing failed: %s" % exc)
334
+ if cp.returncode != 0:
335
+ msg = cp.stderr.decode("utf-8", "replace").strip().splitlines()
336
+ raise Unresolved("git listing failed (rc %d): %s" % (cp.returncode, msg[0] if msg else "no message"))
337
+ names = sorted({os.fsdecode(p) for p in cp.stdout.split(b"\0") if p})
338
+ if not names:
339
+ raise Unresolved("the producer returned no files (no tracked *.test.sh or test-*.sh under %s)" % root)
340
+ return names
341
+
342
+
343
+ def read_member(display, full, counters):
344
+ try:
345
+ st = os.lstat(full)
346
+ except OSError as exc:
347
+ raise Unresolved("listed member cannot be read: %s (%s)" % (display, exc.strerror))
348
+ if not stat.S_ISREG(st.st_mode):
349
+ counters["skipped"] += 1
350
+ return None
351
+ if st.st_size > MAX_FILE:
352
+ counters["skipped"] += 1
353
+ return None
354
+ try:
355
+ with open(full, "rb") as fh:
356
+ data = fh.read()
357
+ except OSError as exc:
358
+ raise Unresolved("listed member cannot be read: %s (%s)" % (display, exc.strerror))
359
+ return data.decode("utf-8", "surrogateescape")
360
+
361
+
362
+ def read_baseline(path):
363
+ rows = collections.Counter()
364
+ try:
365
+ with open(path, "rb") as fh:
366
+ raw = fh.read().decode("utf-8", "surrogateescape")
367
+ except OSError as exc:
368
+ raise Unresolved("baseline unreadable: %s (%s)" % (path, exc.strerror))
369
+ for n, ln in enumerate(raw.split("\n"), 1):
370
+ ln = ln.rstrip("\r")
371
+ if not ln.strip() or ln.startswith("#"):
372
+ continue
373
+ parts = ln.split("\t")
374
+ if len(parts) != 3 or parts[1] not in GATED or not parts[0]:
375
+ raise Unresolved("baseline row %d is malformed (want path TAB class TAB text, class W/P/G): %s" % (n, path))
376
+ rows[(parts[0], parts[1], parts[2])] += 1
377
+ return rows
378
+
379
+
380
+ BASELINE_HEADER = """\
381
+ # ancestor-signal baseline: one row per gated finding, <path> TAB <class> TAB <normalised line>.
382
+ # Classes: W ancestor walk that signals (must read bounded=yes), P signal to the parent, G all-process signal.
383
+ # Maintenance: an in-place replacement of an existing row (same path and class, e.g. after an unrelated edit of
384
+ # that line) is allowed; a net addition needs a reviewer's read; otherwise the file may only shrink. A stale row
385
+ # (no live line) and an unbounded W are red. bounded=yes is LEXICAL (a non-comment SOLEUR_TEST_SUITE_PID
386
+ # comparison with exit, break or return near the walk), not proof of containment.
387
+ # Regenerate: python3 plugins/soleur/scripts/scan-ancestor-signal-helpers.py --write-baseline <this file>
388
+ # (overwrites the whole file: review the diff row by row).
389
+ """
390
+
391
+ REMEDY = (
392
+ "remedy: new W: bound the walk with a non-comment test such as [ \"$p\" = \"$SOLEUR_TEST_SUITE_PID\" ] plus exit, break or return "
393
+ "on that line, then add one baseline row ($$ comparisons read bounded=no; the suite's F10 floor is a minimum, not a pin). "
394
+ "new P or G: rewrite to a nonce-scoped target, or baseline it with a reviewer's read. "
395
+ "stale: delete or swap the row. unbounded: bounding is mandatory, baselining is refused. "
396
+ "--write-baseline overwrites the whole file, so review the diff; untracked files are not scanned "
397
+ "(the producer lists tracked files: git add first). See the section 'Mutating a signalling or "
398
+ "file-removing helper' in plugins/soleur/skills/work/references/work-scratch-sandboxes.md."
399
+ )
400
+
401
+
402
+ def out(msg=""):
403
+ sys.stdout.write(msg + "\n")
404
+
405
+
406
+ def run(argv):
407
+ ap = argparse.ArgumentParser(prog="scan-ancestor-signal-helpers.py", description="Inventory of signal helpers in shell test suites.")
408
+ ap.add_argument("--root", default=".", help="repository root for the tracked-file listing (default: the current directory)")
409
+ ap.add_argument("--baseline", help="baseline file; without it the scan is list-only")
410
+ ap.add_argument("--list", action="store_true", help="print every finding of every class and exit 0")
411
+ ap.add_argument("--write-baseline", metavar="FILE", help="write the gated rows to FILE")
412
+ ap.add_argument("paths", nargs="*", metavar="PATH", help="scan these files instead of the tracked listing")
413
+ args = ap.parse_args(argv)
414
+
415
+ counters = collections.Counter()
416
+ explicit = bool(args.paths)
417
+ names = list(args.paths) if explicit else git_population(args.root)
418
+
419
+ findings = []
420
+ roots = set()
421
+ nfiles = 0
422
+ for name in names:
423
+ full = name if explicit else os.path.join(args.root, name)
424
+ text = read_member(name, full, counters)
425
+ if text is None:
426
+ continue
427
+ nfiles += 1
428
+ if "/" in name:
429
+ roots.add(name.split("/", 1)[0])
430
+ findings.extend(scan_text(name, text, counters))
431
+ findings.sort(key=lambda f: (f.path, f.lineno, f.cls))
432
+
433
+ gated = [f for f in findings if f.cls in GATED]
434
+ listed = [f for f in findings if f.cls == "L"]
435
+ skipped = counters["skipped"]
436
+
437
+ if args.write_baseline:
438
+ if explicit or args.list:
439
+ sys.stderr.write("ancestor-signal scan: --write-baseline rewrites the whole file from the tracked population: pass no PATH and no --list (a partial write would drop every other row)\n")
440
+ return 2
441
+ if skipped:
442
+ raise Unresolved("%d listed member(s) were skipped: refusing to write a baseline that silently drops their rows" % skipped)
443
+ bad = [f for f in gated if f.cls == "W" and f.bounded == "no"]
444
+ if bad:
445
+ for f in bad:
446
+ out("UNBOUNDED W %s:%d: %s" % (f.path, f.lineno, f.text))
447
+ out("ancestor-signal scan: refusing to write a baseline that certifies an unbounded walker (UNBOUNDED above)")
448
+ out("ancestor-signal scan: " + REMEDY)
449
+ return 1
450
+ rows = sorted((f.path, f.cls, f.text) for f in gated)
451
+ tmp = args.write_baseline + ".tmp-%d" % os.getpid()
452
+ try:
453
+ with open(tmp, "wb") as fh:
454
+ fh.write(BASELINE_HEADER.encode("utf-8", "surrogateescape"))
455
+ for r in rows:
456
+ fh.write(("\t".join(r) + "\n").encode("utf-8", "surrogateescape"))
457
+ os.replace(tmp, args.write_baseline)
458
+ finally:
459
+ if os.path.exists(tmp):
460
+ os.unlink(tmp)
461
+ out("ancestor-signal scan: wrote %d baseline rows to %s" % (len(rows), args.write_baseline))
462
+ return 0
463
+
464
+ if args.list or not args.baseline:
465
+ for f in findings:
466
+ out("\t".join((f.cls, f.bounded, f.path, f.text)))
467
+ if counters["overlong"]:
468
+ out("ancestor-signal scan: overlong lines: %d" % counters["overlong"])
469
+ out("ancestor-signal scan: roots: %s" % " ".join(sorted(roots)))
470
+ out("ancestor-signal scan: %d files, %d findings, no baseline: listing only, %d skipped" % (nfiles, len(findings), skipped))
471
+ return 0
472
+
473
+ if skipped:
474
+ raise Unresolved("%d listed member(s) were skipped (a symlink, a special file or over %d bytes): a skipped file is an unchecked file, so no verdict" % (skipped, MAX_FILE))
475
+ base = read_baseline(args.baseline)
476
+ live = collections.Counter((f.path, f.cls, f.text) for f in gated)
477
+ if explicit:
478
+ scanned = set(names)
479
+ base = collections.Counter({k: v for k, v in base.items() if k[0] in scanned})
480
+ matched = sum((live & base).values())
481
+ new = live - base
482
+ stale = base - live
483
+ unbounded = [f for f in gated if f.cls == "W" and f.bounded == "no"]
484
+
485
+ seen = collections.Counter()
486
+ for f in gated:
487
+ key = (f.path, f.cls, f.text)
488
+ seen[key] += 1
489
+ if seen[key] > base.get(key, 0):
490
+ out("NEW %s %s:%d: %s" % (f.cls, f.path, f.lineno, f.text))
491
+ out(" row: %s" % "\t".join(key))
492
+ for key, cnt in sorted(stale.items()):
493
+ for _ in range(cnt):
494
+ out("STALE %s %s: %s" % (key[1], key[0], key[2]))
495
+ for f in unbounded:
496
+ out("UNBOUNDED W %s:%d: %s" % (f.path, f.lineno, f.text))
497
+ red = bool(new or stale or unbounded)
498
+
499
+ if counters["overlong"]:
500
+ out("ancestor-signal scan: overlong lines: %d" % counters["overlong"])
501
+ out("ancestor-signal scan: listed-only (class L): %d" % len(listed))
502
+ out("ancestor-signal scan: roots: %s" % " ".join(sorted(roots)))
503
+ out("ancestor-signal scan: %d files, %d findings, %d baselined, %d new, %d stale, %d unbounded, %d skipped" % (
504
+ nfiles, len(gated), matched, sum(new.values()), sum(stale.values()), len(unbounded), skipped))
505
+ if red:
506
+ out("ancestor-signal scan: " + REMEDY)
507
+ return 1
508
+ out("ancestor-signal scan: CLEAN")
509
+ return 0
510
+
511
+
512
+ def _note(exc, site):
513
+ # Class name and a static site label only. Never str(exc)/repr(exc)/input text: exception text can carry
514
+ # scanned content. `site` is a string literal at every call site.
515
+ # A closed, full or missing stderr (None when fd 2 is closed) must not turn a swallowed error into a crash.
516
+ with contextlib.suppress(OSError, ValueError, AttributeError):
517
+ sys.stderr.write("ancestor-signal scan: swallowed %s at %s\n" % (type(exc).__name__, site))
518
+ sys.stderr.flush()
519
+
520
+
521
+ def flush_stdout():
522
+ try:
523
+ sys.stdout.flush()
524
+ except (OSError, ValueError) as exc:
525
+ _note(exc, "flush-stdout") # a full or closed stdout must not hide the verdict line on stderr
526
+
527
+
528
+ def main():
529
+ try:
530
+ # A replaced stream without reconfigure(): a capability probe, the negative result is normal.
531
+ with contextlib.suppress(AttributeError):
532
+ sys.stdout.reconfigure(errors="surrogateescape")
533
+ sys.stderr.reconfigure(errors="surrogateescape")
534
+ rc = run(sys.argv[1:])
535
+ sys.stdout.flush()
536
+ return rc
537
+ except SystemExit:
538
+ raise
539
+ except Unresolved as exc:
540
+ flush_stdout()
541
+ sys.stderr.write("ancestor-signal scan: UNRESOLVED: %s\n" % exc)
542
+ sys.stderr.flush()
543
+ os._exit(3)
544
+ except (Exception, KeyboardInterrupt) as exc: # an uncaught exception must read as rc 3, never as rc 1 "findings" (other BaseException subclasses: see the docstring)
545
+ try:
546
+ flush_stdout()
547
+ import traceback
548
+ traceback.print_exc()
549
+ sys.stderr.write("ancestor-signal scan: UNRESOLVED: uncaught %s: %s\n" % (type(exc).__name__, exc))
550
+ sys.stderr.flush()
551
+ finally:
552
+ os._exit(3)
553
+
554
+
555
+ if __name__ == "__main__":
556
+ sys.exit(main())