@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,756 @@
1
+ #!/usr/bin/env bash
2
+ # pipeline-tally.sh — running tally of autonomous-pipeline work units (#9403).
3
+ #
4
+ # WHAT IT COUNTS, AND WHY UNITS
5
+ #
6
+ # Autonomous loops (one-shot, work, review, test-fix-loop, drain-*, resolve-*,
7
+ # eval-harness) spend real work — review seats spawned, CI cycles, fix rounds,
8
+ # agent rounds — but print no running tally, so the cost shape of a run is only
9
+ # ever discovered post-hoc (inciting incident: PR #9339, an 11-seat review and
10
+ # ~8 CI cycles for a small fix). This script is the measuring instrument: a
11
+ # per-branch counter file under the session-state root, mutated only through
12
+ # the subcommands below.
13
+ #
14
+ # The counters are UNITS OF WORK, never money — the honest currency for
15
+ # zero-marginal Max-subscription runs (#5086 doctrine, ADR-056). No currency
16
+ # or price token appears in any output, by design and by sentinel.
17
+ #
18
+ # COUNTER FILE
19
+ #
20
+ # <session-state-root>/counters/<slug>
21
+ #
22
+ # <session-state-root> = _session_state_root() from scripts/lib/session-state.sh
23
+ # (SOLEUR_SESSION_STATE_ROOT override, else <git-common-dir>/
24
+ # soleur-session-state, else the /tmp/soleur-session-state-orphan fallback;
25
+ # under the orphan fallback the counters dir gains a -<repo-basename>
26
+ # suffix so two checkouts cannot collide).
27
+ # <slug> = branch name sanitized — every char outside [A-Za-z0-9._-] becomes
28
+ # '-' — PLUS `-<sha1-6>` of the RAW branch name: `feat/x` and `feat-x`
29
+ # sanitize identically and a shared ledger would let one branch's cap
30
+ # latch starve a sibling. Detached HEAD writes `HEAD-<hash>`.
31
+ # hooks/stop-hook.sh reads this ledger via `show` — no second path
32
+ # resolver exists.
33
+ #
34
+ # Flat key=value lines, rewritten wholesale under with_lock:
35
+ # seats / ci_cycles / fix_rounds / agent_rounds (counts, default 0)
36
+ # cap_<dim>=N (0 = unset — persisted at init so caps survive
37
+ # skill-to-skill handoff; argv dies at skill boundaries)
38
+ # warned_<dim>=N (level at which WARN first fired, ask included; 0 = never)
39
+ # capped=<dim> (empty, or the dim that hit its hard cap)
40
+ #
41
+ # CANONICAL PER-SKILL CALL-OUT BLOCK — the literal invocation every
42
+ # instrumented SKILL.md carries (the components.test.ts sentinel anchors on
43
+ # these call forms, comment-stripped — comment-only mentions do not satisfy it):
44
+ #
45
+ # # --- Pipeline tally (soleur #9403) ---
46
+ # bash "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tally.sh" init # once, merge-safe
47
+ # bash "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tally.sh" show # phase boundary
48
+ # bash "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tally.sh" incr <dim> [n] # per op
49
+ # VERDICT="$(bash "${CLAUDE_PLUGIN_ROOT}/scripts/pipeline-tally.sh" gate <dim> [n])"
50
+ # # gate BEFORE each expensive step; [n] = the impending fan-out width so a
51
+ # # bulk spawn can't overshoot the cap unbounded (check-then-blast).
52
+ # # VERDICT == STOP → write
53
+ # # knowledge-base/project/specs/<feature>/session-state.md with
54
+ # # appended `status: budget-capped` + a `budget-capped: <dim>=<n>/<cap>`
55
+ # # line + resume prompt, then exit the phase cleanly — classified stop,
56
+ # # never a blocking prompt in an unattended run (#8611). A parent detects
57
+ # # it via `grep -q budget-capped` on that file.
58
+ # # VERDICT == WARN → continue; the crossing is recorded in the ledger.
59
+ # # VERDICT == UNKNOWN → substrate unreadable; caps unenforced (ship renders
60
+ # # `cap-unenforced`). Every call exits 0 — the tally is fail-open by
61
+ # # contract and must never red a pipeline.
62
+ #
63
+ # COUNTING CONVENTIONS: `seats` = review-panel seats actually spawned (design
64
+ # pass included — `gate seats <panel-size>` before dispatch). `agent_rounds` =
65
+ # orchestration dispatches (one-shot child skills, drain items, resolver
66
+ # fan-outs). `fix_rounds` = fix/retry iterations. `ci_cycles` = CI runs the run
67
+ # itself drove (each push to the PR head). Heterogeneous units land on one dim
68
+ # by design — a cap reads as "work units", not a strict taxonomy.
69
+ #
70
+ # DIMENSIONS: seats | ci_cycles | fix_rounds | agent_rounds
71
+ # (`ci-cycles` is accepted as an alias for `ci_cycles` everywhere a dim is
72
+ # taken). One writer per dimension per skill invocation — a prose `incr` and a
73
+ # workflow `counts:` post for the same dim never both fire.
74
+ #
75
+ # SUBCOMMANDS
76
+ #
77
+ # init [--reset] [--branch <b>]
78
+ # [--max-seats N] [--max-ci-cycles N] [--max-fix-rounds N]
79
+ # [--max-agent-rounds N]
80
+ # Idempotent MERGE: creates the file if absent, preserves counters, merges
81
+ # --max-* flags into cap_<dim>. Prints `tally-init: <slug> <outcome>` where
82
+ # outcome ∈ fresh | continued | reset | capped-reset | stale-reset |
83
+ # repaired:
84
+ # fresh no file existed; new ledger created
85
+ # continued existing ledger kept; argv caps merged. A capped ledger
86
+ # prints `continued capped=<dim>` — the latch is visible.
87
+ # reset --reset given: counts/warned/capped cleared
88
+ # capped-reset ledger carried capped AND new --max-* caps were supplied —
89
+ # the raised-cap resume path; latch AND warned_* cleared,
90
+ # counts preserved. Beats stale-reset: an explicit raised
91
+ # cap is operator intent to continue THIS run; a bare init
92
+ # on the same stale file still stale-resets.
93
+ # stale-reset ledger file untouched for >24h (mtime — inactivity, not
94
+ # age: every gate read and every write refreshes it, so a
95
+ # multi-day run still counting survives): fresh ledger —
96
+ # a stale-ledger continuation must not STOP a fresh run
97
+ # by accident.
98
+ # repaired existing file failed ledger validation — rewritten
99
+ # clean (fail-open) with SOLEUR_TALLY_ERROR
100
+ # reason=unreadable; NEVER reported `continued`, because
101
+ # nothing readable was preserved.
102
+ # CAP SEMANTICS: a ledger carrying `capped` is NOT reset by a bare `init` —
103
+ # it reports `continued` and `capped` persists, so the next `gate` still
104
+ # returns STOP (a budget-capped run cannot be accidentally resumed under
105
+ # the same caps; livelock impossible). `capped` clears only via an explicit
106
+ # `--reset` or by supplying new --max-* caps. Reset clears the LEDGER, never
107
+ # the budget: cap_<dim> values survive every reset form unless the argv
108
+ # overrides them; to drop caps entirely, remove the counter file. Also
109
+ # sweeps sibling counter files with mtime > 30 days.
110
+ # RATCHET GUARD: without --reset, a --max-* LOWER than a persisted nonzero
111
+ # cap is refused and surfaced as a `cap-kept:` line (`cap-kept: <dim>=<kept>`) — a forwarded
112
+ # or defaulted flag must not silently tighten the branch's budget.
113
+ # Armed caps print as `armed: cap:<dim>=<n> …` on every init — a persisted
114
+ # budget is never invisible.
115
+ # Flag validation: values must match ^[1-9][0-9]{0,9}$ — non-numeric,
116
+ # negative, zero, leading-zero forms (`08`), and digit strings that would
117
+ # wrap mod-2^64 are rejected with SOLEUR_TALLY_ERROR reason=bad-flag on
118
+ # stderr and exit 0. `--max-ci_cycles` (underscore) aliases --max-ci-cycles.
119
+ #
120
+ # incr <dim> [n] [--branch <b>]
121
+ # Adds n (default 1, ^[0-9]{1,10}$ validated and 10#-normalized) to <dim> under
122
+ # lock and prints the updated `tally:` line. Missing/unreadable file →
123
+ # stderr SOLEUR_TALLY_ERROR reason=missing-file, stdout UNKNOWN, exit 0 —
124
+ # NEVER auto-creates (auto-create would make an init-after-incr ordering
125
+ # defect undetectable). `--branch <b>` posts to another branch's ledger
126
+ # (fleet-skill item attribution).
127
+ #
128
+ # show [--branch <b>]
129
+ # Absent/unreadable file → UNKNOWN. Else prints
130
+ # `tally: seats=N ci_cycles=N fix_rounds=N agent_rounds=N`, a `cap:<dim>=<n>`
131
+ # token line when caps are set (the stop-hook floor reads this), and, when
132
+ # any is set, `warned:<dim>=<at>` / `capped:<dim>=<cap>` tokens.
133
+ #
134
+ # gate <dim> [n] [--branch <b>]
135
+ # Reads cap_<dim> from the FILE, never argv. Verdict on stdout:
136
+ # STOP capped is set (any dim), or count >= cap_<dim> (cap > 0);
137
+ # sets capped=<dim> when empty — first cap wins, it is sticky.
138
+ # With lookahead n: count+n > cap — STOP WITHOUT latching (a
139
+ # smaller ask may still fit).
140
+ # WARN count+n >= ceil(cap*0.8); records warned_<dim> at the projected
141
+ # level on first fire. (Caps <=4 warn and stop at the same count —
142
+ # the warn band is empty there by construction.)
143
+ # OK otherwise, including cap unset
144
+ # Substrate failure (missing file, unreadable, no flock, lock contention,
145
+ # SOLEUR_DISABLE_SESSION_STATE kill-switch) → stdout UNKNOWN + stderr
146
+ # SOLEUR_TALLY_ERROR reason=<k>. Exit 0 always.
147
+ # An UNKNOWN under configured caps is `cap-unenforced`, never a clean pass.
148
+ #
149
+ # selfcheck
150
+ # Prints SOLEUR_TALLY_OK, exits 0, writes NOTHING — handled before the lib
151
+ # is sourced (session-state.sh creates its state dirs at source time), so
152
+ # it is safe in a read-only sandbox with tmpfs HOME.
153
+ #
154
+ # STDERR DISCIPLINE: SOLEUR_TALLY_ERROR reason=<k> markers; reasons are
155
+ # bad-flag | bad-branch | missing-file | unreadable | no-flock | lock-failed |
156
+ # lock-substrate-disabled | write-failed | lib-missing. `bad-branch` is the
157
+ # _tally_paths refusal class (`--branch` token unsafe for a filename). Lock contention may
158
+ # also print the substrate's own `[warn] lock contended` notice.
159
+ # `unreadable` covers a file that exists but cannot be parsed as a ledger
160
+ # (no `seats=` key, a non-numeric count/cap/warned value, or a capped token
161
+ # outside the dim vocabulary) — a corrupt file must never render as the
162
+ # legitimate `tally: 0` ZERO state.
163
+ #
164
+ # EXIT: always 0 (fail-open — counters must never red a pipeline).
165
+ #
166
+ # macOS: util-linux flock is absent → with_lock unavailable → mutations and
167
+ # gates degrade to UNKNOWN (+reason=no-flock); `show` remains a pure read.
168
+ # Documented limitation until the session-state flock polyfill lands.
169
+
170
+ # xtrace refusal — REQUIRED FIRST EXECUTABLE STATEMENT (lint-shell-trace-
171
+ # credential-refusal, unconditional arm): `_tally_getf` reads via `${!_r}`
172
+ # indirection, which the linter treats as runtime-named credential access —
173
+ # and `-x` prints expanded values. exit 78 is a refusal, not a failure
174
+ # surface, and precedes even the selfcheck fast-path.
175
+ case "$-" in
176
+ *x*) printf '[FATAL] refusing to run under xtrace: this script handles a live credential and -x would print it (see #7797)\n' >&2; exit 78 ;;
177
+ esac
178
+
179
+ # selfcheck fast-path BEFORE sourcing the lib — see header (write-free).
180
+ if [[ "${1:-}" == "selfcheck" ]]; then
181
+ printf 'SOLEUR_TALLY_OK\n'
182
+ exit 0
183
+ fi
184
+
185
+ # Deliberately NOT `set -euo pipefail`: every subcommand is contractually
186
+ # fail-open (exit 0 even on internal error), so all failure surfaces below are
187
+ # explicit checks returning through the SOLEUR_TALLY_ERROR path instead.
188
+ # Every expansion that can be unset is defaulted (${var:-}).
189
+
190
+ TALLY_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P || true)"
191
+ TALLY_LIB="${TALLY_SCRIPT_DIR}/lib/session-state.sh"
192
+ if [[ -r "$TALLY_LIB" ]]; then
193
+ # shellcheck source=lib/session-state.sh
194
+ . "$TALLY_LIB" || true
195
+ fi
196
+
197
+ _tally_err() { printf 'SOLEUR_TALLY_ERROR reason=%s\n' "$1" >&2; }
198
+
199
+ # Owning trap for _tally_write's mktemp allocation (lint-trap-ownership): the
200
+ # write is tmp+mv atomic; a die between alloc and mv would leak <$file>.tmp.*.
201
+ _TALLY_TMP=""
202
+ trap 'rm -f "${_TALLY_TMP:-}"' EXIT
203
+
204
+ # Every char outside [A-Za-z0-9._-] becomes '-'. Generalizes
205
+ # _safe_worktree_name (worktree-manager.sh) — NOT byte-identical to it
206
+ # (`tr '/' '-'` vs full-class), but leases and counters are disjoint
207
+ # namespaces so the divergence is safe.
208
+ _tally_slug() { printf '%s' "$1" | tr -c 'A-Za-z0-9._-' '-'; }
209
+
210
+ # Short discriminator appended to the slug: `feat/x` and `feat-x` slug identically,
211
+ # and a shared ledger would let one branch's cap latch starve a sibling. Hashing
212
+ # the RAW branch name keeps each branch's ledger its own.
213
+ _tally_shorthash() {
214
+ local h
215
+ h=$(printf '%s' "$1" | git hash-object --stdin 2>/dev/null | cut -c1-6)
216
+ # `cut` exits 0 on empty input, so `||` alone can never reach the fallback —
217
+ # test the captured hash instead (a git-less env would re-collide feat/x
218
+ # and feat-x onto `feat-x-`).
219
+ [[ -n "$h" ]] || h=$(printf '%s' "$1" | cksum | cut -d' ' -f1)
220
+ printf '%s' "$h"
221
+ }
222
+
223
+
224
+ # Map _tally_paths rc -> the right error reason (1=bad-branch, 2=lib-missing).
225
+ _tally_paths_err() { case "$1" in 1) _tally_err bad-branch ;; *) _tally_err lib-missing ;; esac; }
226
+
227
+ # Canonicalize a dim token -> seats|ci_cycles|fix_rounds|agent_rounds, or fail.
228
+ _tally_dim() {
229
+ case "$1" in
230
+ seats|ci_cycles|fix_rounds|agent_rounds) printf '%s' "$1" ;;
231
+ ci-cycles) printf 'ci_cycles' ;;
232
+ *) return 1 ;;
233
+ esac
234
+ }
235
+
236
+ # _tally_paths <branch-or-empty> -> T_SLUG T_COUNTERS_DIR T_FILE
237
+ # rc 1 = unsafe branch token refused; rc 2 = no session-state root.
238
+ # _tally_paths_err maps the rc to the right reason marker.
239
+ _tally_paths() {
240
+ local branch="${1:-}"
241
+ if [[ -z "$branch" ]]; then
242
+ branch=$(git branch --show-current 2>/dev/null || true)
243
+ [[ -n "$branch" ]] || branch="HEAD"
244
+ fi
245
+ T_SLUG=$(_tally_slug "$branch")-$(_tally_shorthash "$branch")
246
+ # `.`/`..` survive the slug transform and would compose a path outside
247
+ # counters/ (mv deposits the tmp file in the state root). Same refusal
248
+ # class _validate_worktree_name applies; `--branch '-x'` is flag-eating.
249
+ if [[ "$branch" == -* || "$T_SLUG" == .-* || "$T_SLUG" == ..-* ]]; then
250
+ T_COUNTERS_DIR=""; T_FILE=""; T_SLUG=""
251
+ return 1
252
+ fi
253
+ local root=""
254
+ if command -v _session_state_root >/dev/null 2>&1; then
255
+ root=$(_session_state_root 2>/dev/null || true)
256
+ fi
257
+ if [[ -z "$root" ]]; then
258
+ T_COUNTERS_DIR=""; T_FILE=""
259
+ return 2
260
+ fi
261
+ T_COUNTERS_DIR="$root/counters"
262
+ if [[ "$root" == "/tmp/soleur-session-state-orphan" ]]; then
263
+ # Orphan fallback (not a git repo): suffix the counters dir with the repo
264
+ # basename so counters from different checkouts cannot collide.
265
+ local base
266
+ base=$(basename "$(git rev-parse --show-toplevel 2>/dev/null || printf '%s' "$PWD")")
267
+ T_COUNTERS_DIR="$root/counters-$(_tally_slug "$base")"
268
+ fi
269
+ T_FILE="$T_COUNTERS_DIR/$T_SLUG"
270
+ return 0
271
+ }
272
+
273
+ # Field read: grep+cut, the substrate's own idiom (no jq). Always rc 0.
274
+ _tally_field() {
275
+ grep "^$2=" "$1" 2>/dev/null | head -1 | cut -d= -f2-
276
+ return 0
277
+ }
278
+
279
+ # Is this a parseable ledger? `seats=` is the first key every write emits; a
280
+ # file that lacks it is corrupt/partial and must be reported `unreadable`
281
+ # rather than silently re-read as an all-zero tally (which would masquerade as
282
+ # the legitimate "instrumented, nothing counted" ZERO state). Every count,
283
+ # cap_* and warned_* value must be PURE digits — a digit-prefixed corrupt like
284
+ # `cap_seats=5x` would pass a first-char check, load as 0, and render a budget
285
+ # that looks configured but silently never enforces. `capped=` is whitelisted
286
+ # to the dim vocabulary: a garbage latch would STOP every gate forever.
287
+ # Unknown keys (run_id, started_at from the old schema) are ignored.
288
+ _tally_ledger_ok() {
289
+ [[ -f "$1" && -r "$1" ]] || return 1
290
+ grep -q '^seats=' "$1" 2>/dev/null || return 1
291
+ if grep -qvE '=[0-9]{1,18}$' \
292
+ < <(grep -E '^(seats|ci_cycles|fix_rounds|agent_rounds|cap_[a-z_]+|warned_[a-z_]+)=' "$1" 2>/dev/null); then
293
+ return 1
294
+ fi
295
+ # EVERY capped= line must carry the dim vocabulary or be empty — a duplicate
296
+ # corrupt line after a clean one must not slip past a first-line read.
297
+ if grep -qvE '^capped=(|seats|ci_cycles|fix_rounds|agent_rounds)$' \
298
+ < <(grep -E '^capped=' "$1" 2>/dev/null); then
299
+ return 1
300
+ fi
301
+ return 0
302
+ }
303
+
304
+ # Indirect get/set on the T_* ledger vars (bash 3.2-safe; keys are whitelisted).
305
+ _tally_getf() { local _r="T_$1"; printf '%s' "${!_r}"; }
306
+ _tally_setf() { printf -v "T_$1" '%s' "$2"; }
307
+
308
+ # Load the ledger into T_* globals; missing/corrupt fields default to 0/empty.
309
+ _tally_load() {
310
+ local k v
311
+ for k in seats ci_cycles fix_rounds agent_rounds \
312
+ cap_seats cap_ci_cycles cap_fix_rounds cap_agent_rounds \
313
+ warned_seats warned_ci_cycles warned_fix_rounds warned_agent_rounds; do
314
+ v=""
315
+ [[ -r "$1" ]] && v=$(_tally_field "$1" "$k")
316
+ [[ "$v" =~ ^[0-9]+$ ]] || v=0
317
+ _tally_setf "$k" "$((10#$v))"
318
+ done
319
+ T_capped=""
320
+ if [[ -r "$1" ]]; then
321
+ T_capped=$(_tally_field "$1" capped)
322
+ # Sanitize: an unvetted latch value would reach indirect expansion in
323
+ # `show` (`cap_$T_capped` -> invalid variable name) and mis-STOP gates.
324
+ case "$T_capped" in
325
+ ""|seats|ci_cycles|fix_rounds|agent_rounds) ;;
326
+ *) T_capped="" ;;
327
+ esac
328
+ fi
329
+ return 0
330
+ }
331
+
332
+ # Wholesale rewrite. tmp+mv in the same dir so a crash never leaves a torn
333
+ # ledger; the lock (held by callers) orders concurrent writers.
334
+ _tally_write() {
335
+ local tmp
336
+ mkdir -p "$(dirname "$1")" 2>/dev/null || true
337
+ tmp=$(mktemp "$1.tmp.XXXXXX" 2>/dev/null) || return 1
338
+ _TALLY_TMP="$tmp"
339
+ cat > "$tmp" <<EOF || { rm -f "$tmp"; _TALLY_TMP=""; return 1; }
340
+ seats=$(_tally_getf seats)
341
+ ci_cycles=$(_tally_getf ci_cycles)
342
+ fix_rounds=$(_tally_getf fix_rounds)
343
+ agent_rounds=$(_tally_getf agent_rounds)
344
+ cap_seats=$(_tally_getf cap_seats)
345
+ cap_ci_cycles=$(_tally_getf cap_ci_cycles)
346
+ cap_fix_rounds=$(_tally_getf cap_fix_rounds)
347
+ cap_agent_rounds=$(_tally_getf cap_agent_rounds)
348
+ warned_seats=$(_tally_getf warned_seats)
349
+ warned_ci_cycles=$(_tally_getf warned_ci_cycles)
350
+ warned_fix_rounds=$(_tally_getf warned_fix_rounds)
351
+ warned_agent_rounds=$(_tally_getf warned_agent_rounds)
352
+ capped=$T_capped
353
+ EOF
354
+ if ! mv "$tmp" "$1" 2>/dev/null; then
355
+ rm -f "$tmp" 2>/dev/null || true
356
+ _TALLY_TMP=""
357
+ return 1
358
+ fi
359
+ _TALLY_TMP=""
360
+ return 0
361
+ }
362
+
363
+ _tally_print_line() {
364
+ printf 'tally: seats=%s ci_cycles=%s fix_rounds=%s agent_rounds=%s\n' \
365
+ "$(_tally_getf seats)" "$(_tally_getf ci_cycles)" \
366
+ "$(_tally_getf fix_rounds)" "$(_tally_getf agent_rounds)"
367
+ }
368
+
369
+ # Reap sibling counter files older than 30 days (mtime) — opportunistic
370
+ # housekeeping inside init; never fatal, never the current file's problem.
371
+ # Runs under THIS slug's lock while touching sibling files — benign: only
372
+ # mtime>30d files die, and incr's in-lock existence re-check covers the race.
373
+ _tally_sweep() {
374
+ [[ -n "${T_COUNTERS_DIR:-}" && -d "$T_COUNTERS_DIR" ]] || return 0
375
+ find "$T_COUNTERS_DIR" -maxdepth 1 -type f -mtime +30 -delete 2>/dev/null || true
376
+ return 0
377
+ }
378
+
379
+ # Run an impl under the branch-scoped lock. rc 1 + UNKNOWN + marker on failure.
380
+ _tally_locked() {
381
+ if ! command -v flock >/dev/null 2>&1; then
382
+ _tally_err no-flock
383
+ printf 'UNKNOWN\n'
384
+ return 1
385
+ fi
386
+ if [[ "${SOLEUR_DISABLE_SESSION_STATE:-}" == "1" ]]; then
387
+ # Kill-switch sessions run with_lock's impl UNLOCKED (session-state.sh
388
+ # _acquire_lock_impl returns 0) — a racing read-modify-write would emit a
389
+ # confident tally of lost updates. UNKNOWN is the honest failure.
390
+ _tally_err lock-substrate-disabled
391
+ printf 'UNKNOWN\n'
392
+ return 1
393
+ fi
394
+ if ! command -v with_lock >/dev/null 2>&1; then
395
+ _tally_err lib-missing
396
+ printf 'UNKNOWN\n'
397
+ return 1
398
+ fi
399
+ if ! with_lock "pipeline-tally-$T_SLUG" 10 -- "$@"; then
400
+ _tally_err lock-failed
401
+ printf 'UNKNOWN\n'
402
+ return 1
403
+ fi
404
+ return 0
405
+ }
406
+
407
+ # Cap values: ^[1-9][0-9]{0,9}$ — rejects non-numeric, negative, 0, the
408
+ # leading-zero forms (`08`) that 10# would otherwise silently accept, AND
409
+ # digit strings that wrap mod-2^64 into a different cap than the one asked for.
410
+ _tally_norm_cap() {
411
+ [[ "$1" =~ ^[1-9][0-9]{0,9}$ ]] || return 1
412
+ printf '%s' "$((10#$1))"
413
+ }
414
+
415
+ # --- init -------------------------------------------------------------------
416
+
417
+ _tally_init_locked() {
418
+ local reset="$1" caps_given="$2"
419
+ local n_seats="$3" n_ci="$4" n_fix="$5" n_agent="$6"
420
+ local existed=0 ok=0 outcome
421
+ [[ -f "$T_FILE" ]] && existed=1
422
+ if (( existed )) && _tally_ledger_ok "$T_FILE"; then ok=1; fi
423
+ _tally_load "$T_FILE"
424
+
425
+ # Staleness = 24h of INACTIVITY, keyed on file mtime, not a written key:
426
+ # every incr/gate write bumps it (gate also refreshes it on read), so a
427
+ # multi-day pipeline that crosses the threshold while still counting never
428
+ # gets zeroed mid-run.
429
+ local stale=0 mtime=0
430
+ if (( existed && ok )); then
431
+ mtime=$(stat -c %Y "$T_FILE" 2>/dev/null || stat -f %m "$T_FILE" 2>/dev/null || echo 0)
432
+ [[ "$mtime" =~ ^[0-9]+$ ]] && (( $(date +%s) - 10#$mtime > 86400 )) && stale=1
433
+ fi
434
+
435
+ if (( ! existed )); then
436
+ outcome="fresh"
437
+ elif (( reset )); then
438
+ outcome="reset"
439
+ elif (( ! ok )); then
440
+ # Existing but unreadable/corrupt: rewrite a clean ledger (fail-open — the
441
+ # pipeline must never wedge on state) but do NOT report `continued` —
442
+ # nothing readable was preserved, and a repaired forensic record is not
443
+ # a continuation.
444
+ outcome="repaired"
445
+ _tally_err unreadable
446
+ elif [[ -n "$T_capped" ]] && (( caps_given )); then
447
+ # Raised-cap resume BEATS stale: an explicit `--max-*` argv is operator
448
+ # intent to continue THIS run under a new budget, and the counts are the
449
+ # forensic record the feature exists to keep. (A bare init on the same
450
+ # stale+capped file still stale-resets — argv intent is what disambiguates
451
+ # resume from a new run.)
452
+ outcome="capped-reset"
453
+ elif (( stale )); then
454
+ outcome="stale-reset"
455
+ elif [[ -n "$T_capped" ]]; then
456
+ # Budget-capped ledger + no raised caps: the ledger CONTINUES and `capped`
457
+ # persists, so the next `gate` still returns STOP. See CAP SEMANTICS above.
458
+ outcome="continued capped=$T_capped"
459
+ else
460
+ outcome="continued"
461
+ fi
462
+
463
+ case "$outcome" in
464
+ reset|stale-reset|repaired)
465
+ # Fresh ledger — counts, warnings, capped cleared. cap_<dim> survive:
466
+ # reset clears the ledger, never the budget.
467
+ _tally_setf seats 0; _tally_setf ci_cycles 0
468
+ _tally_setf fix_rounds 0; _tally_setf agent_rounds 0
469
+ _tally_setf warned_seats 0; _tally_setf warned_ci_cycles 0
470
+ _tally_setf warned_fix_rounds 0; _tally_setf warned_agent_rounds 0
471
+ T_capped=""
472
+ ;;
473
+ capped-reset)
474
+ # Same run continuing under a raised budget: clear the latch AND the
475
+ # warned_* markers (they fired against the OLD cap and would annotate
476
+ # the new budget falsely). Counts persist — the branch's cost record is
477
+ # the tally the feature exists to report.
478
+ T_capped=""
479
+ _tally_setf warned_seats 0; _tally_setf warned_ci_cycles 0
480
+ _tally_setf warned_fix_rounds 0; _tally_setf warned_agent_rounds 0
481
+ ;;
482
+ esac
483
+
484
+ # Merge argv caps — RATCHET GUARD: without --reset, a --max-* LOWER than a
485
+ # persisted nonzero cap is refused (a `cap-kept:` line surfaces it). A
486
+ # forwarded or defaulted flag would otherwise silently tighten this branch's
487
+ # budget and false-STOP a later unflagged run.
488
+ _TALLY_KEPT=""
489
+ _tally_merge_cap seats "$n_seats" "$reset"
490
+ _tally_merge_cap ci_cycles "$n_ci" "$reset"
491
+ _tally_merge_cap fix_rounds "$n_fix" "$reset"
492
+ _tally_merge_cap agent_rounds "$n_agent" "$reset"
493
+
494
+ _tally_write "$T_FILE" || { _tally_err write-failed; printf 'UNKNOWN\n'; return 0; }
495
+ _tally_sweep
496
+ printf 'tally-init: %s %s\n' "$T_SLUG" "$outcome"
497
+ # Armed-cap disclosure: a persisted cap from an earlier invocation is
498
+ # otherwise invisible until it stops a run.
499
+ local armed; armed=$(_tally_cap_tokens)
500
+ [[ -n "$armed" ]] && printf 'armed: %s\n' "${armed% }"
501
+ [[ -n "$_TALLY_KEPT" ]] && printf 'cap-kept: %s\n' "${_TALLY_KEPT% }"
502
+ return 0
503
+ }
504
+
505
+ # Trailing-space "cap:<d>=<n> ..." for the nonzero caps — shared by init's
506
+ # armed: line and show's cap: line so the two renderings cannot drift.
507
+ _tally_cap_tokens() {
508
+ local _d _c out=""
509
+ for _d in seats ci_cycles fix_rounds agent_rounds; do
510
+ _c=$(_tally_getf "cap_$_d")
511
+ (( _c > 0 )) && out="${out}cap:${_d}=${_c} "
512
+ done
513
+ printf '%s' "$out"
514
+ }
515
+
516
+ # Merge one --max-* value into cap_<dim>; refuses to lower a persisted nonzero
517
+ # cap unless --reset. Accumulates refusals in _TALLY_KEPT.
518
+ _tally_merge_cap() {
519
+ local dim="$1" newv="$2" reset="$3" old
520
+ [[ -n "$newv" ]] || return 0
521
+ old=$(_tally_getf "cap_$dim")
522
+ if (( ! reset )) && (( old > 0 )) && (( 10#$newv < old )); then
523
+ _TALLY_KEPT="${_TALLY_KEPT}${dim}=${old} "
524
+ return 0
525
+ fi
526
+ _tally_setf "cap_$dim" "$newv"
527
+ return 0
528
+ }
529
+
530
+ cmd_init() {
531
+ local reset=0 caps_given=0 branch="" flag=""
532
+ local n_seats="" n_ci="" n_fix="" n_agent="" v=""
533
+ while [[ $# -gt 0 ]]; do
534
+ # Underscored spellings of a flag alias to its hyphenated form —
535
+ # `--max-ci_cycles` would otherwise silently bad-flag the operator's budget.
536
+ flag=$(printf '%s' "$1" | tr '_' '-')
537
+ case "$flag" in
538
+ --reset) reset=1; shift ;;
539
+ --branch)
540
+ branch="${2:-}"
541
+ [[ -n "$branch" && "$branch" != -* ]] || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
542
+ shift 2 ;;
543
+ --max-seats)
544
+ v=$(_tally_norm_cap "${2:-}") || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
545
+ n_seats=$v; caps_given=1; shift 2 ;;
546
+ --max-ci-cycles)
547
+ v=$(_tally_norm_cap "${2:-}") || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
548
+ n_ci=$v; caps_given=1; shift 2 ;;
549
+ --max-fix-rounds)
550
+ v=$(_tally_norm_cap "${2:-}") || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
551
+ n_fix=$v; caps_given=1; shift 2 ;;
552
+ --max-agent-rounds)
553
+ v=$(_tally_norm_cap "${2:-}") || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
554
+ n_agent=$v; caps_given=1; shift 2 ;;
555
+ *) _tally_err bad-flag; printf 'UNKNOWN\n'; return 0 ;;
556
+ esac
557
+ done
558
+ _tally_paths "$branch" || { _tally_paths_err $?; printf 'UNKNOWN\n'; return 0; }
559
+ _tally_locked _tally_init_locked "$reset" "$caps_given" "$n_seats" "$n_ci" "$n_fix" "$n_agent" || true
560
+ return 0
561
+ }
562
+
563
+ # --- incr -------------------------------------------------------------------
564
+
565
+ _tally_incr_locked() {
566
+ local dim="$1" n="$2"
567
+ if [[ ! -f "$T_FILE" ]]; then
568
+ _tally_err missing-file; printf 'UNKNOWN\n'; return 0
569
+ fi
570
+ if ! _tally_ledger_ok "$T_FILE"; then
571
+ _tally_err unreadable; printf 'UNKNOWN\n'; return 0
572
+ fi
573
+ _tally_load "$T_FILE"
574
+ _tally_setf "$dim" "$(( $(_tally_getf "$dim") + n ))"
575
+ _tally_write "$T_FILE" || { _tally_err write-failed; printf 'UNKNOWN\n'; return 0; }
576
+ _tally_print_line
577
+ return 0
578
+ }
579
+
580
+ cmd_incr() {
581
+ local dim="" n=1 n_set=0 branch=""
582
+ while [[ $# -gt 0 ]]; do
583
+ case "$1" in
584
+ --branch)
585
+ branch="${2:-}"
586
+ [[ -n "$branch" && "$branch" != -* ]] || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
587
+ shift 2 ;;
588
+ -* ) _tally_err bad-flag; printf 'UNKNOWN\n'; return 0 ;;
589
+ *)
590
+ if [[ -z "$dim" ]]; then dim="$1"
591
+ elif (( ! n_set )); then n="$1"; n_set=1
592
+ else _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; fi
593
+ shift ;;
594
+ esac
595
+ done
596
+ dim=$(_tally_dim "${dim:-}") || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
597
+ if [[ ! "$n" =~ ^[0-9]{1,10}$ ]]; then
598
+ _tally_err bad-flag; printf 'UNKNOWN\n'; return 0
599
+ fi
600
+ n=$((10#$n))
601
+ _tally_paths "$branch" || { _tally_paths_err $?; printf 'UNKNOWN\n'; return 0; }
602
+ # Missing file is reported before any lock attempt: the error must fire even
603
+ # where flock is unavailable, and `incr` NEVER creates the ledger.
604
+ if [[ ! -f "$T_FILE" ]]; then
605
+ _tally_err missing-file; printf 'UNKNOWN\n'; return 0
606
+ fi
607
+ _tally_locked _tally_incr_locked "$dim" "$n" || true
608
+ return 0
609
+ }
610
+
611
+ # --- show -------------------------------------------------------------------
612
+
613
+ cmd_show() {
614
+ local branch=""
615
+ while [[ $# -gt 0 ]]; do
616
+ case "$1" in
617
+ --branch)
618
+ branch="${2:-}"
619
+ [[ -n "$branch" && "$branch" != -* ]] || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
620
+ shift 2 ;;
621
+ *) _tally_err bad-flag; printf 'UNKNOWN\n'; return 0 ;;
622
+ esac
623
+ done
624
+ _tally_paths "$branch" || { _tally_paths_err $?; printf 'UNKNOWN\n'; return 0; }
625
+ if [[ ! -f "$T_FILE" ]]; then
626
+ _tally_err missing-file; printf 'UNKNOWN\n'; return 0
627
+ fi
628
+ if ! _tally_ledger_ok "$T_FILE"; then
629
+ _tally_err unreadable; printf 'UNKNOWN\n'; return 0
630
+ fi
631
+ _tally_load "$T_FILE"
632
+ _tally_print_line
633
+ # Second line: configured caps (the stop-hook floor and ship's render both
634
+ # consume this shape — `cap:<dim>=<n>` tokens, same helper init's armed: uses).
635
+ local caps d w
636
+ caps=$(_tally_cap_tokens)
637
+ [[ -n "$caps" ]] && printf '%s\n' "${caps% }"
638
+ # Third line: warned/capped annotations, only when set.
639
+ local ann=""
640
+ for d in seats ci_cycles fix_rounds agent_rounds; do
641
+ w=$(_tally_getf "warned_$d")
642
+ [[ "$w" != "0" ]] && ann="${ann}warned:${d}=${w} "
643
+ done
644
+ [[ -n "$T_capped" ]] && ann="${ann}capped:${T_capped}=$(_tally_getf "cap_$T_capped")"
645
+ ann="${ann% }"
646
+ [[ -n "$ann" ]] && printf '%s\n' "$ann"
647
+ return 0
648
+ }
649
+
650
+ # --- gate -------------------------------------------------------------------
651
+
652
+ _tally_gate_locked() {
653
+ local dim="$1" ask="${2:-0}"
654
+ if [[ ! -f "$T_FILE" ]]; then
655
+ _tally_err missing-file; printf 'UNKNOWN\n'; return 0
656
+ fi
657
+ if ! _tally_ledger_ok "$T_FILE"; then
658
+ _tally_err unreadable; printf 'UNKNOWN\n'; return 0
659
+ fi
660
+ _tally_load "$T_FILE"
661
+ # Refresh mtime on every successful gate read: staleness means "nothing
662
+ # touched the ledger in 24h", and a polling caller (ship's phase-7 gate)
663
+ # IS ledger activity — a quiet-but-live pipeline must not zero itself.
664
+ touch "$T_FILE" 2>/dev/null || true
665
+ # A set `capped` is sticky and global: STOP regardless of which dim is asked.
666
+ if [[ -n "$T_capped" ]]; then
667
+ printf 'STOP\n'; return 0
668
+ fi
669
+ local cap count
670
+ cap=$(_tally_getf "cap_$dim"); count=$(_tally_getf "$dim")
671
+ if (( cap <= 0 )); then
672
+ printf 'OK\n'; return 0
673
+ fi
674
+ if (( count >= cap )); then
675
+ T_capped="$dim"
676
+ # Best-effort persist: the verdict stands even if the write fails (the
677
+ # next gate re-derives STOP from count >= cap).
678
+ _tally_write "$T_FILE" || true
679
+ printf 'STOP\n'; return 0
680
+ fi
681
+ # Lookahead: `gate <dim> <n>` asks "does the impending n-unit step fit?"
682
+ # STOP without latching — a smaller ask may still fit.
683
+ if (( ask > 0 && count + ask > cap )); then
684
+ printf 'STOP\n'; return 0
685
+ fi
686
+ local warn_thresh=$(( (cap * 8 + 9) / 10 )) # ceil(cap * 0.8)
687
+ if (( count + ask >= warn_thresh )); then
688
+ if [[ "$(_tally_getf "warned_$dim")" == "0" ]]; then
689
+ _tally_setf "warned_$dim" "$((count + ask))" # first-fire level incl. the ask
690
+ _tally_write "$T_FILE" || true
691
+ fi
692
+ printf 'WARN\n'; return 0
693
+ fi
694
+ printf 'OK\n'
695
+ return 0
696
+ }
697
+
698
+ cmd_gate() {
699
+ local dim="" ask="" branch=""
700
+ while [[ $# -gt 0 ]]; do
701
+ case "$1" in
702
+ --branch)
703
+ branch="${2:-}"
704
+ [[ -n "$branch" && "$branch" != -* ]] || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
705
+ shift 2 ;;
706
+ *)
707
+ if [[ -z "$dim" ]]; then dim="$1"
708
+ elif [[ -z "$ask" ]]; then ask="$1"
709
+ else _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; fi
710
+ shift ;;
711
+ esac
712
+ done
713
+ dim=$(_tally_dim "${dim:-}") || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
714
+ if [[ -n "$ask" ]]; then
715
+ [[ "$ask" =~ ^[0-9]{1,10}$ ]] || { _tally_err bad-flag; printf 'UNKNOWN\n'; return 0; }
716
+ ask=$((10#$ask))
717
+ else
718
+ ask=0
719
+ fi
720
+ _tally_paths "$branch" || { _tally_paths_err $?; printf 'UNKNOWN\n'; return 0; }
721
+ # Same ordering as cmd_incr: missing-file must win over no-flock.
722
+ if [[ ! -f "$T_FILE" ]]; then
723
+ _tally_err missing-file; printf 'UNKNOWN\n'; return 0
724
+ fi
725
+ _tally_locked _tally_gate_locked "$dim" "$ask" || true
726
+ return 0
727
+ }
728
+
729
+ # --- dispatch ---------------------------------------------------------------
730
+
731
+ _tally_usage() {
732
+ cat <<'EOF'
733
+ usage: pipeline-tally.sh <subcommand> [args]
734
+
735
+ init [--reset] [--branch <b>] [--max-seats N] [--max-ci-cycles N]
736
+ [--max-fix-rounds N] [--max-agent-rounds N]
737
+ incr <dim> [n] [--branch <b>]
738
+ show [--branch <b>]
739
+ gate <dim> [n] [--branch <b>]
740
+ selfcheck
741
+
742
+ dims: seats | ci_cycles (alias ci-cycles) | fix_rounds | agent_rounds
743
+ gate's optional [n] is a lookahead: STOP when count+n would exceed the cap.
744
+ fail-open: every subcommand exits 0; errors are SOLEUR_TALLY_ERROR on stderr.
745
+ EOF
746
+ }
747
+
748
+ case "${1:-}" in
749
+ init) shift; cmd_init "$@" ;;
750
+ incr) shift; cmd_incr "$@" ;;
751
+ show) shift; cmd_show "$@" ;;
752
+ gate) shift; cmd_gate "$@" ;;
753
+ -h|--help|"") _tally_usage ;;
754
+ *) _tally_err bad-flag; _tally_usage >&2 ;;
755
+ esac
756
+ exit 0