raidlock 0.1.0__tar.gz

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 (402) hide show
  1. raidlock-0.1.0/.claude-plugin/marketplace.json +24 -0
  2. raidlock-0.1.0/.claude-plugin/plugin.json +13 -0
  3. raidlock-0.1.0/.dockerignore +7 -0
  4. raidlock-0.1.0/.github/CODEOWNERS +1 -0
  5. raidlock-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  6. raidlock-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  7. raidlock-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +22 -0
  8. raidlock-0.1.0/.github/ISSUE_TEMPLATE/runner_adapter.yml +43 -0
  9. raidlock-0.1.0/.github/dependabot.yml +16 -0
  10. raidlock-0.1.0/.github/pull_request_template.md +13 -0
  11. raidlock-0.1.0/.github/workflows/ci.yml +175 -0
  12. raidlock-0.1.0/.github/workflows/docker-publish.yml +63 -0
  13. raidlock-0.1.0/.github/workflows/pr-title.yml +28 -0
  14. raidlock-0.1.0/.github/workflows/release-please.yml +19 -0
  15. raidlock-0.1.0/.github/workflows/release.yml +118 -0
  16. raidlock-0.1.0/.gitignore +10 -0
  17. raidlock-0.1.0/.gitleaks.toml +74 -0
  18. raidlock-0.1.0/.release-please-manifest.json +3 -0
  19. raidlock-0.1.0/CHANGELOG.md +124 -0
  20. raidlock-0.1.0/CODE_OF_CONDUCT.md +9 -0
  21. raidlock-0.1.0/CONTRIBUTING.md +144 -0
  22. raidlock-0.1.0/Dockerfile +27 -0
  23. raidlock-0.1.0/LICENSE +21 -0
  24. raidlock-0.1.0/PKG-INFO +186 -0
  25. raidlock-0.1.0/PROTOCOL.md +149 -0
  26. raidlock-0.1.0/README.md +153 -0
  27. raidlock-0.1.0/SECURITY.md +77 -0
  28. raidlock-0.1.0/agents/raid-worker.md +19 -0
  29. raidlock-0.1.0/bin/raid +52 -0
  30. raidlock-0.1.0/bin/raidlock +52 -0
  31. raidlock-0.1.0/docs/ARCHITECTURE.md +494 -0
  32. raidlock-0.1.0/docs/RELEASING.md +120 -0
  33. raidlock-0.1.0/docs/assets/README.md +48 -0
  34. raidlock-0.1.0/docs/assets/brand/README.md +54 -0
  35. raidlock-0.1.0/docs/assets/brand/raidlock-lockup-dark.svg +1 -0
  36. raidlock-0.1.0/docs/assets/brand/raidlock-lockup.svg +1 -0
  37. raidlock-0.1.0/docs/assets/brand/raidlock-mark-dark.svg +1 -0
  38. raidlock-0.1.0/docs/assets/brand/raidlock-mark-mono.svg +1 -0
  39. raidlock-0.1.0/docs/assets/brand/raidlock-mark.svg +1 -0
  40. raidlock-0.1.0/docs/assets/brand/raidlock-wordmark-dark.svg +1 -0
  41. raidlock-0.1.0/docs/assets/brand/raidlock-wordmark.svg +1 -0
  42. raidlock-0.1.0/docs/assets/brand/social-preview.png +0 -0
  43. raidlock-0.1.0/docs/assets/brand/social-preview.svg +1 -0
  44. raidlock-0.1.0/docs/assets/demo-60s.cast +32 -0
  45. raidlock-0.1.0/docs/assets/demo.gif +0 -0
  46. raidlock-0.1.0/docs/assets/hero.gif +0 -0
  47. raidlock-0.1.0/docs/assets/hero.mp4 +0 -0
  48. raidlock-0.1.0/docs/assets/ui-plain-desktop.png +0 -0
  49. raidlock-0.1.0/docs/assets/ui-plain-mobile.png +0 -0
  50. raidlock-0.1.0/docs/assets/ui-plain-overview-desktop.png +0 -0
  51. raidlock-0.1.0/docs/assets/ui-plain-overview-mobile.png +0 -0
  52. raidlock-0.1.0/docs/assets/ui-raid-achievements-desktop.png +0 -0
  53. raidlock-0.1.0/docs/assets/ui-raid-desktop.png +0 -0
  54. raidlock-0.1.0/docs/assets/ui-raid-frames-desktop.png +0 -0
  55. raidlock-0.1.0/docs/assets/ui-raid-graph-desktop.png +0 -0
  56. raidlock-0.1.0/docs/assets/ui-raid-map-desktop.png +0 -0
  57. raidlock-0.1.0/docs/assets/ui-raid-mobile.png +0 -0
  58. raidlock-0.1.0/docs/assets/ui-raid-overview-desktop.png +0 -0
  59. raidlock-0.1.0/docs/assets/ui-raid-overview-mobile.png +0 -0
  60. raidlock-0.1.0/docs/assets/ui-raid-replay-desktop.png +0 -0
  61. raidlock-0.1.0/docs/guides/benchmark.md +95 -0
  62. raidlock-0.1.0/docs/guides/commands.md +176 -0
  63. raidlock-0.1.0/docs/guides/concepts.md +43 -0
  64. raidlock-0.1.0/docs/guides/docker.md +128 -0
  65. raidlock-0.1.0/docs/guides/foresight.md +35 -0
  66. raidlock-0.1.0/docs/guides/getting-started.md +102 -0
  67. raidlock-0.1.0/docs/guides/hooks.md +102 -0
  68. raidlock-0.1.0/docs/guides/install.md +184 -0
  69. raidlock-0.1.0/docs/guides/lead-playbook.md +48 -0
  70. raidlock-0.1.0/docs/guides/limits.md +57 -0
  71. raidlock-0.1.0/docs/guides/lore.md +150 -0
  72. raidlock-0.1.0/docs/guides/mcp.md +89 -0
  73. raidlock-0.1.0/docs/guides/multi-provider.md +68 -0
  74. raidlock-0.1.0/docs/guides/native.md +111 -0
  75. raidlock-0.1.0/docs/guides/operations.md +178 -0
  76. raidlock-0.1.0/docs/guides/orchestration.md +274 -0
  77. raidlock-0.1.0/docs/guides/overview.md +108 -0
  78. raidlock-0.1.0/docs/guides/planning.md +78 -0
  79. raidlock-0.1.0/docs/guides/pr.md +104 -0
  80. raidlock-0.1.0/docs/guides/ui.md +237 -0
  81. raidlock-0.1.0/docs/guides/verification.md +75 -0
  82. raidlock-0.1.0/docs/guides/worker-rules.md +50 -0
  83. raidlock-0.1.0/examples/README.md +9 -0
  84. raidlock-0.1.0/examples/claude-only/README.md +25 -0
  85. raidlock-0.1.0/examples/claude-plus-codex/README.md +20 -0
  86. raidlock-0.1.0/examples/demo/README.md +27 -0
  87. raidlock-0.1.0/examples/demo/builder.py +54 -0
  88. raidlock-0.1.0/examples/demo/record.py +169 -0
  89. raidlock-0.1.0/examples/demo/run.sh +270 -0
  90. raidlock-0.1.0/examples/docker/compose.yaml +37 -0
  91. raidlock-0.1.0/examples/multi-workspace/README.md +13 -0
  92. raidlock-0.1.0/examples/playground/README.md +115 -0
  93. raidlock-0.1.0/examples/playground/setup.sh +116 -0
  94. raidlock-0.1.0/hooks/hooks.json +94 -0
  95. raidlock-0.1.0/pyproject.toml +112 -0
  96. raidlock-0.1.0/release-please-config.json +22 -0
  97. raidlock-0.1.0/scripts/bench_overhead.py +11 -0
  98. raidlock-0.1.0/scripts/curate-public.sh +115 -0
  99. raidlock-0.1.0/scripts/demo-60s.sh +192 -0
  100. raidlock-0.1.0/scripts/demo-tape-setup.sh +80 -0
  101. raidlock-0.1.0/scripts/demo.tape +78 -0
  102. raidlock-0.1.0/scripts/docker-smoke.sh +57 -0
  103. raidlock-0.1.0/scripts/overhead_ab.sh +45 -0
  104. raidlock-0.1.0/scripts/render-hero.sh +24 -0
  105. raidlock-0.1.0/skills/raid/SKILL.md +11 -0
  106. raidlock-0.1.0/skills/raidlock/SKILL.md +57 -0
  107. raidlock-0.1.0/skills/raidlock/reference/commands.md +67 -0
  108. raidlock-0.1.0/skills/raidlock/reference/hooks.md +20 -0
  109. raidlock-0.1.0/skills/raidlock/reference/lead.md +30 -0
  110. raidlock-0.1.0/src/raidlock/__init__.py +11 -0
  111. raidlock-0.1.0/src/raidlock/__main__.py +5 -0
  112. raidlock-0.1.0/src/raidlock/_python.py +58 -0
  113. raidlock-0.1.0/src/raidlock/achievements.py +156 -0
  114. raidlock-0.1.0/src/raidlock/approvals.py +237 -0
  115. raidlock-0.1.0/src/raidlock/bench.py +286 -0
  116. raidlock-0.1.0/src/raidlock/bridge/__init__.py +186 -0
  117. raidlock-0.1.0/src/raidlock/budgets.py +178 -0
  118. raidlock-0.1.0/src/raidlock/cli.py +2153 -0
  119. raidlock-0.1.0/src/raidlock/commands_install.py +114 -0
  120. raidlock-0.1.0/src/raidlock/core/__init__.py +26 -0
  121. raidlock-0.1.0/src/raidlock/core/advisories.py +16 -0
  122. raidlock-0.1.0/src/raidlock/core/billing.py +54 -0
  123. raidlock-0.1.0/src/raidlock/core/board.py +2251 -0
  124. raidlock-0.1.0/src/raidlock/core/brief.py +111 -0
  125. raidlock-0.1.0/src/raidlock/core/clock.py +40 -0
  126. raidlock-0.1.0/src/raidlock/core/cost.py +198 -0
  127. raidlock-0.1.0/src/raidlock/core/db.py +608 -0
  128. raidlock-0.1.0/src/raidlock/core/errors.py +52 -0
  129. raidlock-0.1.0/src/raidlock/core/exe.py +6 -0
  130. raidlock-0.1.0/src/raidlock/core/hints.py +32 -0
  131. raidlock-0.1.0/src/raidlock/core/identity.py +285 -0
  132. raidlock-0.1.0/src/raidlock/core/lead.py +758 -0
  133. raidlock-0.1.0/src/raidlock/core/lead_env.py +23 -0
  134. raidlock-0.1.0/src/raidlock/core/lead_hook.py +42 -0
  135. raidlock-0.1.0/src/raidlock/core/leases.py +19 -0
  136. raidlock-0.1.0/src/raidlock/core/lock.py +99 -0
  137. raidlock-0.1.0/src/raidlock/core/messages.py +98 -0
  138. raidlock-0.1.0/src/raidlock/core/migrate.py +579 -0
  139. raidlock-0.1.0/src/raidlock/core/model.py +126 -0
  140. raidlock-0.1.0/src/raidlock/core/models.py +109 -0
  141. raidlock-0.1.0/src/raidlock/core/paths.py +61 -0
  142. raidlock-0.1.0/src/raidlock/core/portable.py +53 -0
  143. raidlock-0.1.0/src/raidlock/core/receipts.py +73 -0
  144. raidlock-0.1.0/src/raidlock/core/registry.py +39 -0
  145. raidlock-0.1.0/src/raidlock/core/repos.py +250 -0
  146. raidlock-0.1.0/src/raidlock/core/safeio.py +201 -0
  147. raidlock-0.1.0/src/raidlock/core/status.py +52 -0
  148. raidlock-0.1.0/src/raidlock/core/store.py +107 -0
  149. raidlock-0.1.0/src/raidlock/core/tokens.py +77 -0
  150. raidlock-0.1.0/src/raidlock/core/transcript.py +208 -0
  151. raidlock-0.1.0/src/raidlock/duel.py +371 -0
  152. raidlock-0.1.0/src/raidlock/foresight.py +191 -0
  153. raidlock-0.1.0/src/raidlock/frames.py +162 -0
  154. raidlock-0.1.0/src/raidlock/gitguard.py +753 -0
  155. raidlock-0.1.0/src/raidlock/guard.py +239 -0
  156. raidlock-0.1.0/src/raidlock/hooks.py +1526 -0
  157. raidlock-0.1.0/src/raidlock/infer.py +205 -0
  158. raidlock-0.1.0/src/raidlock/limits.py +685 -0
  159. raidlock-0.1.0/src/raidlock/lore/__init__.py +22 -0
  160. raidlock-0.1.0/src/raidlock/lore/approval.py +145 -0
  161. raidlock-0.1.0/src/raidlock/lore/capture.py +146 -0
  162. raidlock-0.1.0/src/raidlock/lore/cli.py +109 -0
  163. raidlock-0.1.0/src/raidlock/lore/distill.py +17 -0
  164. raidlock-0.1.0/src/raidlock/lore/frontmatter.py +56 -0
  165. raidlock-0.1.0/src/raidlock/lore/inject.py +127 -0
  166. raidlock-0.1.0/src/raidlock/lore/vault.py +264 -0
  167. raidlock-0.1.0/src/raidlock/mcp/__init__.py +34 -0
  168. raidlock-0.1.0/src/raidlock/mcp/resources.py +72 -0
  169. raidlock-0.1.0/src/raidlock/mcp/server.py +184 -0
  170. raidlock-0.1.0/src/raidlock/mcp/tools.py +178 -0
  171. raidlock-0.1.0/src/raidlock/notify.py +144 -0
  172. raidlock-0.1.0/src/raidlock/party.py +239 -0
  173. raidlock-0.1.0/src/raidlock/pr.py +575 -0
  174. raidlock-0.1.0/src/raidlock/prsync.py +318 -0
  175. raidlock-0.1.0/src/raidlock/recipes/README.md +34 -0
  176. raidlock-0.1.0/src/raidlock/recipes/__init__.py +105 -0
  177. raidlock-0.1.0/src/raidlock/recipes/docs-refresh.md +15 -0
  178. raidlock-0.1.0/src/raidlock/recipes/multi-repo-refactor.md +15 -0
  179. raidlock-0.1.0/src/raidlock/recipes/security-audit.md +27 -0
  180. raidlock-0.1.0/src/raidlock/recipes/upgrade-deps.md +15 -0
  181. raidlock-0.1.0/src/raidlock/reputation.py +194 -0
  182. raidlock-0.1.0/src/raidlock/resume.py +329 -0
  183. raidlock-0.1.0/src/raidlock/resurrect.py +419 -0
  184. raidlock-0.1.0/src/raidlock/routing.py +419 -0
  185. raidlock-0.1.0/src/raidlock/runners/__init__.py +16 -0
  186. raidlock-0.1.0/src/raidlock/runners/base.py +341 -0
  187. raidlock-0.1.0/src/raidlock/runners/brief.py +176 -0
  188. raidlock-0.1.0/src/raidlock/runners/claude_code.py +121 -0
  189. raidlock-0.1.0/src/raidlock/runners/cli.py +110 -0
  190. raidlock-0.1.0/src/raidlock/runners/codex.py +114 -0
  191. raidlock-0.1.0/src/raidlock/runners/gemini.py +64 -0
  192. raidlock-0.1.0/src/raidlock/runners/isolation.py +391 -0
  193. raidlock-0.1.0/src/raidlock/runners/policy.py +123 -0
  194. raidlock-0.1.0/src/raidlock/runners/runner.py +921 -0
  195. raidlock-0.1.0/src/raidlock/runners/shell.py +35 -0
  196. raidlock-0.1.0/src/raidlock/runners/verifycache.py +93 -0
  197. raidlock-0.1.0/src/raidlock/runners/workspace.py +376 -0
  198. raidlock-0.1.0/src/raidlock/scan.py +357 -0
  199. raidlock-0.1.0/src/raidlock/snapshot.py +151 -0
  200. raidlock-0.1.0/src/raidlock/treasury.py +210 -0
  201. raidlock-0.1.0/src/raidlock/tui.py +223 -0
  202. raidlock-0.1.0/src/raidlock/web/__init__.py +5 -0
  203. raidlock-0.1.0/src/raidlock/web/achievements/view.css +19 -0
  204. raidlock-0.1.0/src/raidlock/web/achievements/view.js +58 -0
  205. raidlock-0.1.0/src/raidlock/web/bosses/view.css +19 -0
  206. raidlock-0.1.0/src/raidlock/web/bosses/view.js +46 -0
  207. raidlock-0.1.0/src/raidlock/web/cli.py +90 -0
  208. raidlock-0.1.0/src/raidlock/web/data.py +687 -0
  209. raidlock-0.1.0/src/raidlock/web/export.py +153 -0
  210. raidlock-0.1.0/src/raidlock/web/frames/view.css +25 -0
  211. raidlock-0.1.0/src/raidlock/web/frames/view.js +63 -0
  212. raidlock-0.1.0/src/raidlock/web/graph/__init__.py +142 -0
  213. raidlock-0.1.0/src/raidlock/web/graph/view.css +33 -0
  214. raidlock-0.1.0/src/raidlock/web/graph/view.js +136 -0
  215. raidlock-0.1.0/src/raidlock/web/raidmap/__init__.py +205 -0
  216. raidlock-0.1.0/src/raidlock/web/raidmap/view.css +15 -0
  217. raidlock-0.1.0/src/raidlock/web/raidmap/view.js +47 -0
  218. raidlock-0.1.0/src/raidlock/web/replay/__init__.py +258 -0
  219. raidlock-0.1.0/src/raidlock/web/replay/view.css +13 -0
  220. raidlock-0.1.0/src/raidlock/web/replay/view.js +127 -0
  221. raidlock-0.1.0/src/raidlock/web/server.py +292 -0
  222. raidlock-0.1.0/src/raidlock/web/static/app.css +851 -0
  223. raidlock-0.1.0/src/raidlock/web/static/app.js +2102 -0
  224. raidlock-0.1.0/src/raidlock/web/static/fonts/OFL.txt +93 -0
  225. raidlock-0.1.0/src/raidlock/web/static/fonts/cinzel-600.woff2 +0 -0
  226. raidlock-0.1.0/src/raidlock/web/static/fonts/cinzel-700.woff2 +0 -0
  227. raidlock-0.1.0/src/raidlock/web/static/icon-32.png +0 -0
  228. raidlock-0.1.0/src/raidlock/web/static/icon-raid.svg +1 -0
  229. raidlock-0.1.0/src/raidlock/web/static/icon.svg +1 -0
  230. raidlock-0.1.0/src/raidlock/web/static/index.html +122 -0
  231. raidlock-0.1.0/tests/achievements/conftest.py +9 -0
  232. raidlock-0.1.0/tests/achievements/test_achievements.py +204 -0
  233. raidlock-0.1.0/tests/approvals/conftest.py +33 -0
  234. raidlock-0.1.0/tests/approvals/test_approvals.py +172 -0
  235. raidlock-0.1.0/tests/bench/budget.json +106 -0
  236. raidlock-0.1.0/tests/bench/test_overhead.py +88 -0
  237. raidlock-0.1.0/tests/budgets/test_budgets.py +195 -0
  238. raidlock-0.1.0/tests/conftest.py +9 -0
  239. raidlock-0.1.0/tests/core/conftest.py +86 -0
  240. raidlock-0.1.0/tests/core/corehelpers.py +59 -0
  241. raidlock-0.1.0/tests/core/test_advisories.py +43 -0
  242. raidlock-0.1.0/tests/core/test_brief_untrusted.py +25 -0
  243. raidlock-0.1.0/tests/core/test_bug_sweep.py +197 -0
  244. raidlock-0.1.0/tests/core/test_cli.py +349 -0
  245. raidlock-0.1.0/tests/core/test_cli_extensions.py +72 -0
  246. raidlock-0.1.0/tests/core/test_cli_safe_credentials.py +21 -0
  247. raidlock-0.1.0/tests/core/test_cli_team.py +262 -0
  248. raidlock-0.1.0/tests/core/test_cli_ux.py +241 -0
  249. raidlock-0.1.0/tests/core/test_concurrency.py +98 -0
  250. raidlock-0.1.0/tests/core/test_cost.py +184 -0
  251. raidlock-0.1.0/tests/core/test_db_initialization.py +32 -0
  252. raidlock-0.1.0/tests/core/test_handover_security.py +208 -0
  253. raidlock-0.1.0/tests/core/test_identity.py +145 -0
  254. raidlock-0.1.0/tests/core/test_lead_token.py +117 -0
  255. raidlock-0.1.0/tests/core/test_leases.py +235 -0
  256. raidlock-0.1.0/tests/core/test_long_loops.py +36 -0
  257. raidlock-0.1.0/tests/core/test_messages.py +127 -0
  258. raidlock-0.1.0/tests/core/test_migration.py +658 -0
  259. raidlock-0.1.0/tests/core/test_model.py +269 -0
  260. raidlock-0.1.0/tests/core/test_multi_agent_collaboration.py +340 -0
  261. raidlock-0.1.0/tests/core/test_paths.py +134 -0
  262. raidlock-0.1.0/tests/core/test_portable.py +71 -0
  263. raidlock-0.1.0/tests/core/test_process_anchor.py +207 -0
  264. raidlock-0.1.0/tests/core/test_release_audit.py +310 -0
  265. raidlock-0.1.0/tests/core/test_safeio.py +82 -0
  266. raidlock-0.1.0/tests/core/test_scale.py +237 -0
  267. raidlock-0.1.0/tests/core/test_status_registry.py +120 -0
  268. raidlock-0.1.0/tests/core/test_store_lock.py +111 -0
  269. raidlock-0.1.0/tests/core/test_transcript.py +150 -0
  270. raidlock-0.1.0/tests/core/test_transcript_events.py +37 -0
  271. raidlock-0.1.0/tests/core/test_ui_host.py +66 -0
  272. raidlock-0.1.0/tests/core/test_verification_membership.py +110 -0
  273. raidlock-0.1.0/tests/core/test_verify_cache.py +216 -0
  274. raidlock-0.1.0/tests/core/test_verify_receipts.py +290 -0
  275. raidlock-0.1.0/tests/duel/conftest.py +33 -0
  276. raidlock-0.1.0/tests/duel/test_duel.py +242 -0
  277. raidlock-0.1.0/tests/e2e/test_demo.py +70 -0
  278. raidlock-0.1.0/tests/enforce/README.md +44 -0
  279. raidlock-0.1.0/tests/enforce/conftest.py +51 -0
  280. raidlock-0.1.0/tests/enforce/test_must_not.py +316 -0
  281. raidlock-0.1.0/tests/examples/test_demo_60s.py +77 -0
  282. raidlock-0.1.0/tests/examples/test_playground.py +76 -0
  283. raidlock-0.1.0/tests/extras/test_notify_snapshot.py +328 -0
  284. raidlock-0.1.0/tests/fixtures/.gitattributes +1 -0
  285. raidlock-0.1.0/tests/fixtures/v1-board/LOG.md +16 -0
  286. raidlock-0.1.0/tests/fixtures/v1-board/agents.json +27 -0
  287. raidlock-0.1.0/tests/fixtures/v1-board/cards/active.md +14 -0
  288. raidlock-0.1.0/tests/fixtures/v1-board/cards/checking.md +14 -0
  289. raidlock-0.1.0/tests/fixtures/v1-board/cards/finished.md +14 -0
  290. raidlock-0.1.0/tests/fixtures/v1-board/cards/first.md +24 -0
  291. raidlock-0.1.0/tests/fixtures/v1-board/cards/queued.md +14 -0
  292. raidlock-0.1.0/tests/fixtures/v1-board/cards/second.md +21 -0
  293. raidlock-0.1.0/tests/fixtures/v1-board/cards/waiting.md +14 -0
  294. raidlock-0.1.0/tests/fixtures/v1-board/inbox/w-one.jsonl +1 -0
  295. raidlock-0.1.0/tests/fixtures/v1-board/inbox/worker.jsonl +1 -0
  296. raidlock-0.1.0/tests/fixtures/v1-board/leases.json +34 -0
  297. raidlock-0.1.0/tests/fixtures/v1-board/settings.json +7 -0
  298. raidlock-0.1.0/tests/fixtures/v1-board/teams.json +12 -0
  299. raidlock-0.1.0/tests/foresight/test_foresight.py +210 -0
  300. raidlock-0.1.0/tests/frames/conftest.py +9 -0
  301. raidlock-0.1.0/tests/frames/test_frames.py +119 -0
  302. raidlock-0.1.0/tests/guard/test_guard.py +331 -0
  303. raidlock-0.1.0/tests/guard/test_guard_security.py +91 -0
  304. raidlock-0.1.0/tests/hooks/conftest.py +168 -0
  305. raidlock-0.1.0/tests/hooks/fixtures/post_claim.json +1 -0
  306. raidlock-0.1.0/tests/hooks/fixtures/pre_bash_board_write.json +1 -0
  307. raidlock-0.1.0/tests/hooks/fixtures/pre_bash_plain.json +1 -0
  308. raidlock-0.1.0/tests/hooks/fixtures/pre_bash_subagent_done.json +1 -0
  309. raidlock-0.1.0/tests/hooks/fixtures/pre_write_allow.json +1 -0
  310. raidlock-0.1.0/tests/hooks/fixtures/pre_write_board_file.json +1 -0
  311. raidlock-0.1.0/tests/hooks/fixtures/pre_write_main_free.json +1 -0
  312. raidlock-0.1.0/tests/hooks/fixtures/pre_write_main_held.json +1 -0
  313. raidlock-0.1.0/tests/hooks/fixtures/pre_write_no_task.json +1 -0
  314. raidlock-0.1.0/tests/hooks/fixtures/pre_write_notebook.json +1 -0
  315. raidlock-0.1.0/tests/hooks/fixtures/pre_write_other_fence.json +1 -0
  316. raidlock-0.1.0/tests/hooks/fixtures/session_start.json +1 -0
  317. raidlock-0.1.0/tests/hooks/fixtures/subagent_stop.json +1 -0
  318. raidlock-0.1.0/tests/hooks/test_compound_targets.py +74 -0
  319. raidlock-0.1.0/tests/hooks/test_git_guard.py +343 -0
  320. raidlock-0.1.0/tests/hooks/test_hook_interpreter.py +147 -0
  321. raidlock-0.1.0/tests/hooks/test_hook_security.py +358 -0
  322. raidlock-0.1.0/tests/hooks/test_hooks.py +396 -0
  323. raidlock-0.1.0/tests/hooks/test_install_commands.py +133 -0
  324. raidlock-0.1.0/tests/hooks/test_native_bridge.py +781 -0
  325. raidlock-0.1.0/tests/hooks/test_separate_session_worker.py +103 -0
  326. raidlock-0.1.0/tests/infer/test_infer.py +241 -0
  327. raidlock-0.1.0/tests/limits/conftest.py +14 -0
  328. raidlock-0.1.0/tests/limits/test_limits.py +345 -0
  329. raidlock-0.1.0/tests/lore/conftest.py +28 -0
  330. raidlock-0.1.0/tests/lore/lorehelpers.py +115 -0
  331. raidlock-0.1.0/tests/lore/test_lore_approval.py +188 -0
  332. raidlock-0.1.0/tests/lore/test_lore_capture.py +105 -0
  333. raidlock-0.1.0/tests/lore/test_lore_inject.py +95 -0
  334. raidlock-0.1.0/tests/lore/test_lore_vault.py +168 -0
  335. raidlock-0.1.0/tests/mcp/conftest.py +56 -0
  336. raidlock-0.1.0/tests/mcp/mcphelpers.py +32 -0
  337. raidlock-0.1.0/tests/mcp/test_mcp_protocol.py +238 -0
  338. raidlock-0.1.0/tests/mcp/test_mcp_resources.py +41 -0
  339. raidlock-0.1.0/tests/mcp/test_mcp_tools.py +141 -0
  340. raidlock-0.1.0/tests/mcp/test_mcp_workspace.py +63 -0
  341. raidlock-0.1.0/tests/party/conftest.py +9 -0
  342. raidlock-0.1.0/tests/party/test_party.py +210 -0
  343. raidlock-0.1.0/tests/portable.py +14 -0
  344. raidlock-0.1.0/tests/pr/conftest.py +26 -0
  345. raidlock-0.1.0/tests/pr/prhelpers.py +128 -0
  346. raidlock-0.1.0/tests/pr/test_pr.py +516 -0
  347. raidlock-0.1.0/tests/prsync/conftest.py +34 -0
  348. raidlock-0.1.0/tests/prsync/test_prsync.py +399 -0
  349. raidlock-0.1.0/tests/recipes/test_recipes.py +142 -0
  350. raidlock-0.1.0/tests/reputation/test_reputation.py +268 -0
  351. raidlock-0.1.0/tests/resume/conftest.py +33 -0
  352. raidlock-0.1.0/tests/resume/test_resume.py +291 -0
  353. raidlock-0.1.0/tests/resurrect/conftest.py +33 -0
  354. raidlock-0.1.0/tests/resurrect/fake_claude.py +42 -0
  355. raidlock-0.1.0/tests/resurrect/test_resurrect.py +363 -0
  356. raidlock-0.1.0/tests/routing/conftest.py +33 -0
  357. raidlock-0.1.0/tests/routing/test_routing.py +195 -0
  358. raidlock-0.1.0/tests/runners/conftest.py +24 -0
  359. raidlock-0.1.0/tests/runners/fake_agent.py +51 -0
  360. raidlock-0.1.0/tests/runners/fixtures/claude_read_only.jsonl +7 -0
  361. raidlock-0.1.0/tests/runners/fixtures/codex_read_only.jsonl +9 -0
  362. raidlock-0.1.0/tests/runners/fixtures/codex_workspace_write.jsonl +7 -0
  363. raidlock-0.1.0/tests/runners/runhelpers.py +103 -0
  364. raidlock-0.1.0/tests/runners/test_recovery_integration.py +72 -0
  365. raidlock-0.1.0/tests/runners/test_runner_adapters.py +232 -0
  366. raidlock-0.1.0/tests/runners/test_runner_brief.py +86 -0
  367. raidlock-0.1.0/tests/runners/test_runner_delegate.py +438 -0
  368. raidlock-0.1.0/tests/runners/test_runner_live.py +43 -0
  369. raidlock-0.1.0/tests/runners/test_runner_policy.py +76 -0
  370. raidlock-0.1.0/tests/runners/test_runner_security.py +597 -0
  371. raidlock-0.1.0/tests/runners/test_sensitive_disposal.py +76 -0
  372. raidlock-0.1.0/tests/runners/test_verify_cleanup.py +66 -0
  373. raidlock-0.1.0/tests/scan/fixtures/paths.patch +10 -0
  374. raidlock-0.1.0/tests/scan/fixtures/secrets.patch +12 -0
  375. raidlock-0.1.0/tests/scan/test_scan.py +199 -0
  376. raidlock-0.1.0/tests/treasury/conftest.py +9 -0
  377. raidlock-0.1.0/tests/treasury/test_nonfinite.py +22 -0
  378. raidlock-0.1.0/tests/treasury/test_treasury.py +138 -0
  379. raidlock-0.1.0/tests/tui/empty.txt +21 -0
  380. raidlock-0.1.0/tests/tui/populated.txt +26 -0
  381. raidlock-0.1.0/tests/tui/test_tui.py +198 -0
  382. raidlock-0.1.0/tests/web/browser.py +110 -0
  383. raidlock-0.1.0/tests/web/conftest.py +9 -0
  384. raidlock-0.1.0/tests/web/demo.py +398 -0
  385. raidlock-0.1.0/tests/web/fxfeed.py +105 -0
  386. raidlock-0.1.0/tests/web/graph/test_graph.py +253 -0
  387. raidlock-0.1.0/tests/web/layout_states.py +55 -0
  388. raidlock-0.1.0/tests/web/party/test_party_web.py +85 -0
  389. raidlock-0.1.0/tests/web/raidmap/test_raidmap.py +143 -0
  390. raidlock-0.1.0/tests/web/replay/test_replay.py +248 -0
  391. raidlock-0.1.0/tests/web/serving.py +105 -0
  392. raidlock-0.1.0/tests/web/test_approvals_web.py +28 -0
  393. raidlock-0.1.0/tests/web/test_focus_view.py +529 -0
  394. raidlock-0.1.0/tests/web/test_fx.py +163 -0
  395. raidlock-0.1.0/tests/web/test_layout_browser.py +136 -0
  396. raidlock-0.1.0/tests/web/test_layout_logic.py +145 -0
  397. raidlock-0.1.0/tests/web/test_pr_pill.py +39 -0
  398. raidlock-0.1.0/tests/web/test_web_browser.py +685 -0
  399. raidlock-0.1.0/tests/web/test_web_fds.py +61 -0
  400. raidlock-0.1.0/tests/web/test_web_features.py +166 -0
  401. raidlock-0.1.0/tests/web/test_web_server.py +428 -0
  402. raidlock-0.1.0/uv.lock +372 -0
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "raidlock",
3
+ "owner": {
4
+ "name": "agi1clj",
5
+ "url": "https://github.com/agi1clj"
6
+ },
7
+ "metadata": {
8
+ "description": "raidlock plugin for Claude Code"
9
+ },
10
+ "plugins": [
11
+ {
12
+ "name": "raidlock",
13
+ "source": "./",
14
+ "description": "Lease-and-review board for coding agents: path locks enforced by hooks, a lead-only done gate, heartbeats and handbacks.",
15
+ "version": "0.1.0",
16
+ "author": {
17
+ "name": "agi1clj"
18
+ },
19
+ "homepage": "https://github.com/agi1clj/raidlock",
20
+ "repository": "https://github.com/agi1clj/raidlock",
21
+ "license": "MIT"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "raidlock",
3
+ "version": "0.1.0",
4
+ "description": "Lease-and-review board for coding agents: path locks enforced by hooks, a lead-only done gate, heartbeats and handbacks.",
5
+ "author": {
6
+ "name": "agi1clj",
7
+ "url": "https://github.com/agi1clj"
8
+ },
9
+ "homepage": "https://github.com/agi1clj/raidlock",
10
+ "repository": "https://github.com/agi1clj/raidlock",
11
+ "license": "MIT",
12
+ "keywords": ["agents", "coordination", "leases", "locks", "review"]
13
+ }
@@ -0,0 +1,7 @@
1
+ *
2
+ !pyproject.toml
3
+ !README.md
4
+ !LICENSE
5
+ !src/
6
+ **/__pycache__
7
+ **/*.pyc
@@ -0,0 +1 @@
1
+ * @agi1clj
@@ -0,0 +1,49 @@
1
+ name: Bug report
2
+ description: Something does not work as documented.
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: what
7
+ attributes:
8
+ label: What happened
9
+ description: What you did, what you expected and what happened instead.
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: repro
14
+ attributes:
15
+ label: Steps to reproduce
16
+ description: Commands, from a fresh board if possible. Do not paste secrets or private transcript content.
17
+ render: shell
18
+ validations:
19
+ required: true
20
+ - type: input
21
+ id: version
22
+ attributes:
23
+ label: raidlock version
24
+ placeholder: raidlock --version
25
+ validations:
26
+ required: true
27
+ - type: dropdown
28
+ id: os
29
+ attributes:
30
+ label: OS
31
+ options: [Linux, macOS, Windows, Other]
32
+ validations:
33
+ required: true
34
+ - type: input
35
+ id: python
36
+ attributes:
37
+ label: Python version
38
+ - type: dropdown
39
+ id: runtime
40
+ attributes:
41
+ label: Runtime involved
42
+ multiple: true
43
+ options: [Claude Code, Codex CLI, Gemini CLI, shell, web UI, none]
44
+ - type: textarea
45
+ id: logs
46
+ attributes:
47
+ label: Output
48
+ description: Error output or `--json` output.
49
+ render: text
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Report a security vulnerability
4
+ url: https://github.com/agi1clj/raidlock/security/advisories/new
5
+ about: Report vulnerabilities privately, not as an issue.
@@ -0,0 +1,22 @@
1
+ name: Feature request
2
+ description: Suggest a change or new feature.
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem
9
+ description: What are you trying to do, and what gets in the way today?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposal
16
+ description: What should raidlock do? Note any change to PROTOCOL.md.
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives considered
@@ -0,0 +1,43 @@
1
+ name: Runner adapter request
2
+ description: Ask for raidlock to delegate quests to another agent CLI.
3
+ labels: [runner-adapter]
4
+ body:
5
+ - type: input
6
+ id: cli
7
+ attributes:
8
+ label: Agent CLI
9
+ placeholder: name and link
10
+ validations:
11
+ required: true
12
+ - type: input
13
+ id: version
14
+ attributes:
15
+ label: CLI version tested
16
+ validations:
17
+ required: true
18
+ - type: textarea
19
+ id: headless
20
+ attributes:
21
+ label: Headless invocation
22
+ description: How to run it non-interactively with a prompt on stdin, a working directory and a model.
23
+ render: shell
24
+ validations:
25
+ required: true
26
+ - type: textarea
27
+ id: sandbox
28
+ attributes:
29
+ label: Sandbox and approval modes
30
+ description: Read-only and write modes, and how to keep approvals on. Links to the CLI's docs.
31
+ validations:
32
+ required: true
33
+ - type: textarea
34
+ id: events
35
+ attributes:
36
+ label: Machine-readable output
37
+ description: Event stream or JSON output format, structured output support, and where usage (tokens, cost) is reported.
38
+ - type: checkboxes
39
+ id: willing
40
+ attributes:
41
+ label: Contribution
42
+ options:
43
+ - label: I can open a pull request with the adapter and recorded-event tests
@@ -0,0 +1,16 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ groups:
8
+ github-actions:
9
+ patterns: ["*"]
10
+ - package-ecosystem: pip
11
+ directory: /
12
+ schedule:
13
+ interval: weekly
14
+ groups:
15
+ python:
16
+ patterns: ["*"]
@@ -0,0 +1,13 @@
1
+ ## What and why
2
+
3
+ ## How it was tested
4
+
5
+ ## Checklist
6
+
7
+ - [ ] Every commit is signed off (`git commit -s`)
8
+ - [ ] Tests added or updated; the suite passes locally
9
+ - [ ] `CHANGELOG.md` updated under Unreleased (if users would notice)
10
+ - [ ] Docs updated (README, PROTOCOL.md, docs/guides) if behavior changed
11
+ - [ ] PROTOCOL.md changes called out above
12
+ - [ ] No code comments, no new runtime dependency, no secrets or real board data in fixtures
13
+ - [ ] Workflow changes pass actionlint and pin actions to commit SHAs
@@ -0,0 +1,175 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ env:
17
+ PYTHONUTF8: "1"
18
+ UV_NO_PROGRESS: "1"
19
+
20
+ jobs:
21
+ actionlint:
22
+ name: actionlint
23
+ runs-on: ubuntu-latest
24
+ timeout-minutes: 5
25
+ env:
26
+ ACTIONLINT_VERSION: 1.7.12
27
+ ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
28
+ steps:
29
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
30
+ with:
31
+ persist-credentials: false
32
+ - name: Install actionlint
33
+ run: |
34
+ archive="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
35
+ curl -fsSLo "$archive" "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/${archive}"
36
+ echo "${ACTIONLINT_SHA256} ${archive}" | sha256sum -c -
37
+ tar -xzf "$archive" actionlint
38
+ - name: Run actionlint
39
+ run: ./actionlint -color
40
+
41
+ test:
42
+ name: test (${{ matrix.os }}, py${{ matrix.python }})
43
+ runs-on: ${{ matrix.os }}
44
+ timeout-minutes: 30
45
+ continue-on-error: ${{ matrix.os == 'windows-latest' }}
46
+ strategy:
47
+ fail-fast: false
48
+ matrix:
49
+ os: [ubuntu-latest, macos-latest]
50
+ python: ["3.11", "3.12", "3.13", "3.14", "3.15"]
51
+ include:
52
+ - os: windows-latest
53
+ python: "3.11"
54
+ defaults:
55
+ run:
56
+ shell: bash
57
+ steps:
58
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
59
+ with:
60
+ persist-credentials: false
61
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e
62
+ with:
63
+ python-version: ${{ matrix.python }}
64
+ - name: Run tests
65
+ run: uv run --locked pytest --ignore=tests/web
66
+
67
+ playwright:
68
+ name: web UI (Playwright)
69
+ runs-on: ubuntu-latest
70
+ timeout-minutes: 20
71
+ steps:
72
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
73
+ with:
74
+ persist-credentials: false
75
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e
76
+ with:
77
+ python-version: "3.13"
78
+ - name: Install browser
79
+ run: |
80
+ uv sync --locked --extra ui-test
81
+ uv run --locked playwright install --with-deps chromium
82
+ - name: Run web tests
83
+ run: uv run --locked pytest tests/web
84
+ - name: Upload traces on failure
85
+ if: failure()
86
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
87
+ with:
88
+ name: playwright-results
89
+ path: test-results/
90
+ if-no-files-found: ignore
91
+ retention-days: 7
92
+
93
+ lint:
94
+ runs-on: ubuntu-latest
95
+ timeout-minutes: 10
96
+ steps:
97
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
98
+ with:
99
+ persist-credentials: false
100
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e
101
+ with:
102
+ python-version: "3.11"
103
+ - name: Ruff lint
104
+ run: uv run --locked --with ruff==0.15.14 ruff check
105
+ - name: Ruff format
106
+ if: always()
107
+ run: uv run --locked --with ruff==0.15.14 ruff format --check
108
+
109
+ overhead:
110
+ name: idle overhead
111
+ runs-on: ubuntu-latest
112
+ timeout-minutes: 10
113
+ steps:
114
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
115
+ with:
116
+ persist-credentials: false
117
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e
118
+ with:
119
+ python-version: "3.11"
120
+ - name: Measure idle overhead
121
+ run: |
122
+ uv run --locked python scripts/bench_overhead.py --runs 5 --tokenizer estimate > overhead.json 2> overhead.md
123
+ head -n 1 overhead.md
124
+ cat overhead.md >> "$GITHUB_STEP_SUMMARY"
125
+
126
+ types:
127
+ runs-on: ubuntu-latest
128
+ timeout-minutes: 10
129
+ steps:
130
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
131
+ with:
132
+ persist-credentials: false
133
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e
134
+ with:
135
+ python-version: "3.11"
136
+ - name: Pyright
137
+ run: uv run --locked --with pyright==1.1.408 pyright src/raidlock
138
+
139
+ docker:
140
+ name: docker image
141
+ continue-on-error: true
142
+ runs-on: ubuntu-latest
143
+ timeout-minutes: 20
144
+ env:
145
+ IMAGE: raidlock:ci
146
+ TRIVY_VERSION: 0.75.0
147
+ TRIVY_SHA256: c6e65abddb348e25f10549df887045629cf28cc72453cd1c63acb717316b3f3f
148
+ steps:
149
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
150
+ with:
151
+ persist-credentials: false
152
+ - name: Build image
153
+ run: docker build --platform linux/amd64 -t "$IMAGE" .
154
+ - name: Allow unprivileged user namespaces
155
+ run: |
156
+ if [ -e /proc/sys/kernel/apparmor_restrict_unprivileged_userns ]; then
157
+ sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
158
+ fi
159
+ - name: Smoke test in a hardened container
160
+ run: |
161
+ docker run --rm --read-only --cap-drop ALL --security-opt no-new-privileges \
162
+ --security-opt apparmor=unconfined --network none \
163
+ --tmpfs /tmp:uid=10001,gid=10001,mode=1777 \
164
+ --tmpfs /home/raid:uid=10001,gid=10001,mode=0700 \
165
+ --tmpfs /workspace:uid=10001,gid=10001,mode=0700 \
166
+ -v "$PWD/scripts/docker-smoke.sh:/smoke.sh:ro" \
167
+ --entrypoint sh "$IMAGE" /smoke.sh
168
+ - name: Install Trivy
169
+ run: |
170
+ archive="trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz"
171
+ curl -fsSLo "$archive" "https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/${archive}"
172
+ echo "${TRIVY_SHA256} ${archive}" | sha256sum -c -
173
+ tar -xzf "$archive" trivy
174
+ - name: Trivy image scan
175
+ run: ./trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed --no-progress "$IMAGE"
@@ -0,0 +1,63 @@
1
+ name: Docker publish
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: docker-publish-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ env:
15
+ IMAGE: ghcr.io/agi1clj/raidlock
16
+
17
+ jobs:
18
+ publish:
19
+ name: Build, sign and push
20
+ runs-on: ubuntu-latest
21
+ timeout-minutes: 45
22
+ permissions:
23
+ contents: read
24
+ packages: write
25
+ id-token: write
26
+ steps:
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
28
+ with:
29
+ persist-credentials: false
30
+ - name: Check tag matches project version
31
+ run: |
32
+ version="$(python3 -c 'import runpy; print(runpy.run_path("src/raidlock/__init__.py")["__version__"])')"
33
+ if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
34
+ echo "::error::tag ${GITHUB_REF_NAME} does not match project version ${version}"
35
+ exit 1
36
+ fi
37
+ echo "VERSION=${version}" >> "$GITHUB_ENV"
38
+ - uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1
39
+ - uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069
40
+ - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f
41
+ with:
42
+ registry: ghcr.io
43
+ username: ${{ github.actor }}
44
+ password: ${{ github.token }}
45
+ - name: Build and push
46
+ id: build
47
+ uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc
48
+ with:
49
+ context: .
50
+ platforms: linux/amd64,linux/arm64
51
+ push: true
52
+ sbom: true
53
+ provenance: mode=max
54
+ tags: |
55
+ ${{ env.IMAGE }}:${{ env.VERSION }}
56
+ ${{ env.IMAGE }}:latest
57
+ - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6
58
+ with:
59
+ cosign-release: v3.1.3
60
+ - name: Sign image
61
+ env:
62
+ DIGEST: ${{ steps.build.outputs.digest }}
63
+ run: cosign sign --yes "${IMAGE}@${DIGEST}"
@@ -0,0 +1,28 @@
1
+ name: PR title
2
+
3
+ on:
4
+ pull_request_target:
5
+ types: [opened, edited, synchronize, reopened, ready_for_review]
6
+
7
+ permissions:
8
+ pull-requests: read
9
+
10
+ jobs:
11
+ title:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50
15
+ env:
16
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17
+ with:
18
+ types: |
19
+ feat
20
+ fix
21
+ docs
22
+ test
23
+ refactor
24
+ perf
25
+ ci
26
+ build
27
+ chore
28
+ revert
@@ -0,0 +1,19 @@
1
+ name: Release please
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ permissions:
8
+ contents: write
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ release-please:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7
16
+ with:
17
+ token: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }}
18
+ config-file: release-please-config.json
19
+ manifest-file: .release-please-manifest.json
@@ -0,0 +1,118 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ concurrency:
11
+ group: release-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ build:
16
+ name: Build sdist and wheel
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 10
19
+ steps:
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
21
+ with:
22
+ persist-credentials: false
23
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e
24
+ with:
25
+ python-version: "3.13"
26
+ - name: Check tag matches project version
27
+ run: |
28
+ version="$(python -c 'import runpy; print(runpy.run_path("src/raidlock/__init__.py")["__version__"])')"
29
+ if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
30
+ echo "::error::tag ${GITHUB_REF_NAME} does not match project version ${version}"
31
+ exit 1
32
+ fi
33
+ - name: Check distribution metadata versions
34
+ run: |
35
+ python - <<'PYTHON'
36
+ import json
37
+ import runpy
38
+ import tomllib
39
+ from pathlib import Path
40
+ version = runpy.run_path("src/raidlock/__init__.py")["__version__"]
41
+ plugin = json.loads(Path(".claude-plugin/plugin.json").read_text())
42
+ marketplace = json.loads(Path(".claude-plugin/marketplace.json").read_text())
43
+ lock = tomllib.loads(Path("uv.lock").read_text())
44
+ project = tomllib.loads(Path("pyproject.toml").read_text())
45
+ assert project["project"]["version"] == version
46
+ assert plugin["version"] == version
47
+ assert all(p["version"] == version for p in marketplace["plugins"])
48
+ assert next(p["version"] for p in lock["package"] if p["name"] == "raidlock") == version
49
+ PYTHON
50
+ - name: Build
51
+ run: uv build
52
+ - name: Extract release notes from CHANGELOG
53
+ run: |
54
+ version="${GITHUB_REF_NAME#v}"
55
+ awk -v v="$version" '
56
+ index($0, "## [" v "]") == 1 { found = 1; next }
57
+ found && /^## \[/ { exit }
58
+ found && /^\[[^]]+\]: / { exit }
59
+ found { print }
60
+ ' CHANGELOG.md > dist/RELEASE_NOTES.md
61
+ if [ ! -s dist/RELEASE_NOTES.md ]; then
62
+ echo "::error::no CHANGELOG.md section for ${version}"
63
+ exit 1
64
+ fi
65
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9
66
+ with:
67
+ name: dist
68
+ path: dist/
69
+ if-no-files-found: error
70
+ retention-days: 7
71
+
72
+ pypi:
73
+ name: Publish to PyPI
74
+ needs: build
75
+ runs-on: ubuntu-latest
76
+ timeout-minutes: 10
77
+ environment:
78
+ name: pypi
79
+ url: https://pypi.org/p/raidlock
80
+ permissions:
81
+ id-token: write
82
+ steps:
83
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333
84
+ with:
85
+ name: dist
86
+ path: dist/
87
+ - name: Keep only distributions
88
+ run: rm -f dist/RELEASE_NOTES.md
89
+ - uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086
90
+ with:
91
+ attestations: true
92
+
93
+ github-release:
94
+ name: GitHub release
95
+ needs: pypi
96
+ runs-on: ubuntu-latest
97
+ timeout-minutes: 10
98
+ permissions:
99
+ contents: write
100
+ steps:
101
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333
102
+ with:
103
+ name: dist
104
+ path: dist/
105
+ - name: Create release
106
+ env:
107
+ GH_TOKEN: ${{ github.token }}
108
+ GH_REPO: ${{ github.repository }}
109
+ run: |
110
+ if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
111
+ gh release upload "$GITHUB_REF_NAME" dist/*.tar.gz dist/*.whl
112
+ exit 0
113
+ fi
114
+ gh release create "$GITHUB_REF_NAME" \
115
+ --title "$GITHUB_REF_NAME" \
116
+ --notes-file dist/RELEASE_NOTES.md \
117
+ --verify-tag \
118
+ dist/*.tar.gz dist/*.whl
@@ -0,0 +1,10 @@
1
+ .board/
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ node_modules/
10
+ test-results/