relaydeck 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 (486) hide show
  1. relaydeck-0.1.0/.dockerignore +16 -0
  2. relaydeck-0.1.0/.github/APPROVED_CONTRIBUTORS +19 -0
  3. relaydeck-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +67 -0
  4. relaydeck-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  5. relaydeck-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +46 -0
  6. relaydeck-0.1.0/.github/dependabot.yml +29 -0
  7. relaydeck-0.1.0/.github/pull_request_template.md +30 -0
  8. relaydeck-0.1.0/.github/workflows/approve-contributor.yml +117 -0
  9. relaydeck-0.1.0/.github/workflows/ci.yml +134 -0
  10. relaydeck-0.1.0/.github/workflows/docker-fast.yml +59 -0
  11. relaydeck-0.1.0/.github/workflows/e2e.yml +77 -0
  12. relaydeck-0.1.0/.github/workflows/issue-gate.yml +110 -0
  13. relaydeck-0.1.0/.github/workflows/pr-gate.yml +108 -0
  14. relaydeck-0.1.0/.github/workflows/release.yml +85 -0
  15. relaydeck-0.1.0/.github/workflows/version-bump.yml +60 -0
  16. relaydeck-0.1.0/.gitignore +58 -0
  17. relaydeck-0.1.0/AGENTS.md +555 -0
  18. relaydeck-0.1.0/CHANGELOG.md +89 -0
  19. relaydeck-0.1.0/CONTRIBUTING.md +137 -0
  20. relaydeck-0.1.0/CREDITS.md +99 -0
  21. relaydeck-0.1.0/LICENSE +21 -0
  22. relaydeck-0.1.0/Makefile +106 -0
  23. relaydeck-0.1.0/PKG-INFO +335 -0
  24. relaydeck-0.1.0/README.md +302 -0
  25. relaydeck-0.1.0/SECURITY.md +32 -0
  26. relaydeck-0.1.0/TESTING.md +208 -0
  27. relaydeck-0.1.0/docs/RELEASE.md +79 -0
  28. relaydeck-0.1.0/docs/playwright.md +389 -0
  29. relaydeck-0.1.0/plugins/__init__.py +19 -0
  30. relaydeck-0.1.0/plugins/bundle.toml +30 -0
  31. relaydeck-0.1.0/plugins/dashboard/SKILL.md +66 -0
  32. relaydeck-0.1.0/plugins/dashboard/__init__.py +1 -0
  33. relaydeck-0.1.0/plugins/dashboard/plugin.py +69 -0
  34. relaydeck-0.1.0/plugins/dashboard/plugin.toml +21 -0
  35. relaydeck-0.1.0/plugins/external_agents/__init__.py +2 -0
  36. relaydeck-0.1.0/plugins/external_agents/detector.py +223 -0
  37. relaydeck-0.1.0/plugins/external_agents/harness.py +83 -0
  38. relaydeck-0.1.0/plugins/external_agents/models.py +183 -0
  39. relaydeck-0.1.0/plugins/external_agents/plugin.py +640 -0
  40. relaydeck-0.1.0/plugins/external_agents/plugin.toml +30 -0
  41. relaydeck-0.1.0/plugins/external_agents/probes.py +165 -0
  42. relaydeck-0.1.0/plugins/external_agents/static/panel.js +365 -0
  43. relaydeck-0.1.0/plugins/external_agents/store.py +97 -0
  44. relaydeck-0.1.0/plugins/file_watcher/__init__.py +0 -0
  45. relaydeck-0.1.0/plugins/file_watcher/plugin.py +341 -0
  46. relaydeck-0.1.0/plugins/file_watcher/plugin.toml +9 -0
  47. relaydeck-0.1.0/plugins/gateway/__init__.py +0 -0
  48. relaydeck-0.1.0/plugins/gateway/plugin.py +218 -0
  49. relaydeck-0.1.0/plugins/gateway/plugin.toml +15 -0
  50. relaydeck-0.1.0/plugins/github/__init__.py +0 -0
  51. relaydeck-0.1.0/plugins/github/enrich.py +135 -0
  52. relaydeck-0.1.0/plugins/github/plugin.py +912 -0
  53. relaydeck-0.1.0/plugins/github/plugin.toml +50 -0
  54. relaydeck-0.1.0/plugins/github/poller.py +447 -0
  55. relaydeck-0.1.0/plugins/github/rules.py +302 -0
  56. relaydeck-0.1.0/plugins/github/spawn.py +151 -0
  57. relaydeck-0.1.0/plugins/github/static/panel.js +1440 -0
  58. relaydeck-0.1.0/plugins/harnesses/__init__.py +1 -0
  59. relaydeck-0.1.0/plugins/harnesses/antigravity/__init__.py +1 -0
  60. relaydeck-0.1.0/plugins/harnesses/antigravity/agent.py +302 -0
  61. relaydeck-0.1.0/plugins/harnesses/antigravity/plugin.py +17 -0
  62. relaydeck-0.1.0/plugins/harnesses/antigravity/plugin.toml +9 -0
  63. relaydeck-0.1.0/plugins/harnesses/claude_code/__init__.py +0 -0
  64. relaydeck-0.1.0/plugins/harnesses/claude_code/agent.py +471 -0
  65. relaydeck-0.1.0/plugins/harnesses/claude_code/plugin.py +23 -0
  66. relaydeck-0.1.0/plugins/harnesses/claude_code/plugin.toml +9 -0
  67. relaydeck-0.1.0/plugins/harnesses/codex/__init__.py +0 -0
  68. relaydeck-0.1.0/plugins/harnesses/codex/agent.py +613 -0
  69. relaydeck-0.1.0/plugins/harnesses/codex/plugin.py +17 -0
  70. relaydeck-0.1.0/plugins/harnesses/codex/plugin.toml +9 -0
  71. relaydeck-0.1.0/plugins/harnesses/cursor/__init__.py +1 -0
  72. relaydeck-0.1.0/plugins/harnesses/cursor/agent.py +390 -0
  73. relaydeck-0.1.0/plugins/harnesses/cursor/plugin.py +18 -0
  74. relaydeck-0.1.0/plugins/harnesses/cursor/plugin.toml +9 -0
  75. relaydeck-0.1.0/plugins/harnesses/opencode/__init__.py +0 -0
  76. relaydeck-0.1.0/plugins/harnesses/opencode/agent.py +394 -0
  77. relaydeck-0.1.0/plugins/harnesses/opencode/plugin.py +19 -0
  78. relaydeck-0.1.0/plugins/harnesses/opencode/plugin.toml +9 -0
  79. relaydeck-0.1.0/plugins/harnesses/pi/__init__.py +0 -0
  80. relaydeck-0.1.0/plugins/harnesses/pi/agent.py +390 -0
  81. relaydeck-0.1.0/plugins/harnesses/pi/plugin.py +56 -0
  82. relaydeck-0.1.0/plugins/harnesses/pi/plugin.toml +17 -0
  83. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/__init__.py +0 -0
  84. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/agent.py +365 -0
  85. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/pi_engine.py +930 -0
  86. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/pi_extension.ts +186 -0
  87. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/pi_startup.ts +210 -0
  88. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/plugin.py +135 -0
  89. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/plugin.toml +24 -0
  90. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/prompt.py +255 -0
  91. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/calls.js +111 -0
  92. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/context.js +109 -0
  93. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/pi_install.js +183 -0
  94. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/widget_chat.js +235 -0
  95. relaydeck-0.1.0/plugins/harnesses/relaydeck_native/tools.py +405 -0
  96. relaydeck-0.1.0/plugins/hitl/__init__.py +1 -0
  97. relaydeck-0.1.0/plugins/hitl/plugin.py +389 -0
  98. relaydeck-0.1.0/plugins/hitl/plugin.toml +27 -0
  99. relaydeck-0.1.0/plugins/loop/__init__.py +0 -0
  100. relaydeck-0.1.0/plugins/loop/agent.py +415 -0
  101. relaydeck-0.1.0/plugins/loop/plugin.py +51 -0
  102. relaydeck-0.1.0/plugins/loop/plugin.toml +13 -0
  103. relaydeck-0.1.0/plugins/messaging/SKILL.md +133 -0
  104. relaydeck-0.1.0/plugins/messaging/__init__.py +0 -0
  105. relaydeck-0.1.0/plugins/messaging/plugin.py +1403 -0
  106. relaydeck-0.1.0/plugins/messaging/plugin.toml +45 -0
  107. relaydeck-0.1.0/plugins/messaging/static/tile_compose.js +108 -0
  108. relaydeck-0.1.0/plugins/messaging/static/tile_inbox.js +253 -0
  109. relaydeck-0.1.0/plugins/metering/__init__.py +0 -0
  110. relaydeck-0.1.0/plugins/metering/plugin.py +354 -0
  111. relaydeck-0.1.0/plugins/metering/plugin.toml +25 -0
  112. relaydeck-0.1.0/plugins/metering/static/fleet.js +191 -0
  113. relaydeck-0.1.0/plugins/metering/static/tile_cost.js +86 -0
  114. relaydeck-0.1.0/plugins/metering/static/tile_tokens.js +95 -0
  115. relaydeck-0.1.0/plugins/prompts/SKILL.md +74 -0
  116. relaydeck-0.1.0/plugins/prompts/__init__.py +1 -0
  117. relaydeck-0.1.0/plugins/prompts/plugin.py +465 -0
  118. relaydeck-0.1.0/plugins/prompts/plugin.toml +64 -0
  119. relaydeck-0.1.0/plugins/prompts/static/tile_prompts.js +113 -0
  120. relaydeck-0.1.0/plugins/providers/__init__.py +0 -0
  121. relaydeck-0.1.0/plugins/providers/anthropic/__init__.py +0 -0
  122. relaydeck-0.1.0/plugins/providers/anthropic/plugin.py +109 -0
  123. relaydeck-0.1.0/plugins/providers/anthropic/plugin.toml +10 -0
  124. relaydeck-0.1.0/plugins/providers/ollama/__init__.py +0 -0
  125. relaydeck-0.1.0/plugins/providers/ollama/plugin.py +12 -0
  126. relaydeck-0.1.0/plugins/providers/ollama/plugin.toml +9 -0
  127. relaydeck-0.1.0/plugins/providers/openai/__init__.py +0 -0
  128. relaydeck-0.1.0/plugins/providers/openai/plugin.py +100 -0
  129. relaydeck-0.1.0/plugins/providers/openai/plugin.toml +10 -0
  130. relaydeck-0.1.0/plugins/providers/openrouter/__init__.py +0 -0
  131. relaydeck-0.1.0/plugins/providers/openrouter/plugin.py +224 -0
  132. relaydeck-0.1.0/plugins/providers/openrouter/plugin.toml +10 -0
  133. relaydeck-0.1.0/plugins/py.typed +1 -0
  134. relaydeck-0.1.0/plugins/registry.yaml +43 -0
  135. relaydeck-0.1.0/plugins/skills/FLEET_SKILL.md +62 -0
  136. relaydeck-0.1.0/plugins/skills/PLUGIN_AUTHORING_SKILL.md +215 -0
  137. relaydeck-0.1.0/plugins/skills/__init__.py +0 -0
  138. relaydeck-0.1.0/plugins/skills/commands.py +203 -0
  139. relaydeck-0.1.0/plugins/skills/manager.py +295 -0
  140. relaydeck-0.1.0/plugins/skills/plugin.py +204 -0
  141. relaydeck-0.1.0/plugins/skills/plugin.toml +44 -0
  142. relaydeck-0.1.0/plugins/skills/routes.py +121 -0
  143. relaydeck-0.1.0/plugins/skills/static/panel.js +374 -0
  144. relaydeck-0.1.0/plugins/telegram/SKILL.md +169 -0
  145. relaydeck-0.1.0/plugins/telegram/__init__.py +0 -0
  146. relaydeck-0.1.0/plugins/telegram/conversations.py +188 -0
  147. relaydeck-0.1.0/plugins/telegram/inbound_map.py +123 -0
  148. relaydeck-0.1.0/plugins/telegram/plugin.py +2421 -0
  149. relaydeck-0.1.0/plugins/telegram/plugin.toml +112 -0
  150. relaydeck-0.1.0/plugins/telegram/routes.py +378 -0
  151. relaydeck-0.1.0/plugins/telegram/static/conversations.js +71 -0
  152. relaydeck-0.1.0/plugins/telegram/static/panel.js +1487 -0
  153. relaydeck-0.1.0/plugins/telegram/static/tile_chats.js +107 -0
  154. relaydeck-0.1.0/plugins/telegram/typing_sessions.py +132 -0
  155. relaydeck-0.1.0/plugins/telegram/worker.py +600 -0
  156. relaydeck-0.1.0/plugins/theme/SKILL.md +70 -0
  157. relaydeck-0.1.0/plugins/theme/__init__.py +1 -0
  158. relaydeck-0.1.0/plugins/theme/plugin.py +75 -0
  159. relaydeck-0.1.0/plugins/theme/plugin.toml +21 -0
  160. relaydeck-0.1.0/plugins/usage_limits/__init__.py +0 -0
  161. relaydeck-0.1.0/plugins/usage_limits/core.py +153 -0
  162. relaydeck-0.1.0/plugins/usage_limits/plugin.py +469 -0
  163. relaydeck-0.1.0/plugins/usage_limits/plugin.toml +43 -0
  164. relaydeck-0.1.0/plugins/usage_limits/static/panel.js +135 -0
  165. relaydeck-0.1.0/plugins/usage_limits/static/tile.js +105 -0
  166. relaydeck-0.1.0/plugins/vault/__init__.py +0 -0
  167. relaydeck-0.1.0/plugins/vault/plugin.py +518 -0
  168. relaydeck-0.1.0/plugins/vault/plugin.toml +24 -0
  169. relaydeck-0.1.0/plugins/vault/static/vault.js +171 -0
  170. relaydeck-0.1.0/plugins/vault/store.py +338 -0
  171. relaydeck-0.1.0/pyproject.toml +106 -0
  172. relaydeck-0.1.0/relaydeck/__init__.py +55 -0
  173. relaydeck-0.1.0/relaydeck/__main__.py +8 -0
  174. relaydeck-0.1.0/relaydeck/agents_base.py +108 -0
  175. relaydeck-0.1.0/relaydeck/atomicio.py +37 -0
  176. relaydeck-0.1.0/relaydeck/audit.py +222 -0
  177. relaydeck-0.1.0/relaydeck/auth.py +155 -0
  178. relaydeck-0.1.0/relaydeck/auth_tokens.py +245 -0
  179. relaydeck-0.1.0/relaydeck/automation/__init__.py +42 -0
  180. relaydeck-0.1.0/relaydeck/automation/actions.py +481 -0
  181. relaydeck-0.1.0/relaydeck/automation/schedule.py +63 -0
  182. relaydeck-0.1.0/relaydeck/automation_runs.py +296 -0
  183. relaydeck-0.1.0/relaydeck/bundles.py +85 -0
  184. relaydeck-0.1.0/relaydeck/channels.py +337 -0
  185. relaydeck-0.1.0/relaydeck/config.py +449 -0
  186. relaydeck-0.1.0/relaydeck/daemon.py +258 -0
  187. relaydeck-0.1.0/relaydeck/dashboard_commands.py +170 -0
  188. relaydeck-0.1.0/relaydeck/db.py +1790 -0
  189. relaydeck-0.1.0/relaydeck/harness/__init__.py +27 -0
  190. relaydeck-0.1.0/relaydeck/harness/base.py +1246 -0
  191. relaydeck-0.1.0/relaydeck/harness_model.py +297 -0
  192. relaydeck-0.1.0/relaydeck/harness_options.py +686 -0
  193. relaydeck-0.1.0/relaydeck/integrations/__init__.py +239 -0
  194. relaydeck-0.1.0/relaydeck/integrations/classifier.py +79 -0
  195. relaydeck-0.1.0/relaydeck/integrations/claude.py +324 -0
  196. relaydeck-0.1.0/relaydeck/layouts.py +172 -0
  197. relaydeck-0.1.0/relaydeck/local_providers.py +143 -0
  198. relaydeck-0.1.0/relaydeck/maintenance.py +109 -0
  199. relaydeck-0.1.0/relaydeck/messages.py +616 -0
  200. relaydeck-0.1.0/relaydeck/metrics.py +382 -0
  201. relaydeck-0.1.0/relaydeck/model_invocations.py +296 -0
  202. relaydeck-0.1.0/relaydeck/model_roles.py +282 -0
  203. relaydeck-0.1.0/relaydeck/models/__init__.py +0 -0
  204. relaydeck-0.1.0/relaydeck/models_dev.py +372 -0
  205. relaydeck-0.1.0/relaydeck/orchestrator.py +1354 -0
  206. relaydeck-0.1.0/relaydeck/plugin.py +2088 -0
  207. relaydeck-0.1.0/relaydeck/plugin_disabled.py +88 -0
  208. relaydeck-0.1.0/relaydeck/plugin_install.py +478 -0
  209. relaydeck-0.1.0/relaydeck/plugin_lock.py +195 -0
  210. relaydeck-0.1.0/relaydeck/plugin_manifest.py +340 -0
  211. relaydeck-0.1.0/relaydeck/plugin_registry.py +126 -0
  212. relaydeck-0.1.0/relaydeck/plugin_settings.py +216 -0
  213. relaydeck-0.1.0/relaydeck/preferences.py +194 -0
  214. relaydeck-0.1.0/relaydeck/prompt_composition.py +185 -0
  215. relaydeck-0.1.0/relaydeck/prompts.py +711 -0
  216. relaydeck-0.1.0/relaydeck/provider.py +13 -0
  217. relaydeck-0.1.0/relaydeck/provider_config.py +102 -0
  218. relaydeck-0.1.0/relaydeck/providers_extra.py +284 -0
  219. relaydeck-0.1.0/relaydeck/providers_ollama.py +145 -0
  220. relaydeck-0.1.0/relaydeck/py.typed +1 -0
  221. relaydeck-0.1.0/relaydeck/screen.py +93 -0
  222. relaydeck-0.1.0/relaydeck/sdk.py +1689 -0
  223. relaydeck-0.1.0/relaydeck/semantic_engine.py +263 -0
  224. relaydeck-0.1.0/relaydeck/skills.py +639 -0
  225. relaydeck-0.1.0/relaydeck/skills_cache.py +247 -0
  226. relaydeck-0.1.0/relaydeck/state.py +299 -0
  227. relaydeck-0.1.0/relaydeck/tasks.py +322 -0
  228. relaydeck-0.1.0/relaydeck/testing.py +391 -0
  229. relaydeck-0.1.0/relaydeck/themes.py +451 -0
  230. relaydeck-0.1.0/relaydeck/tls.py +144 -0
  231. relaydeck-0.1.0/relaydeck/transports/__init__.py +0 -0
  232. relaydeck-0.1.0/relaydeck/transports/api.py +3668 -0
  233. relaydeck-0.1.0/relaydeck/transports/attach.py +429 -0
  234. relaydeck-0.1.0/relaydeck/transports/cli.py +7000 -0
  235. relaydeck-0.1.0/relaydeck/transports/view.py +1246 -0
  236. relaydeck-0.1.0/relaydeck/transports/viewers/__init__.py +212 -0
  237. relaydeck-0.1.0/relaydeck/transports/viewers/ghostty.py +362 -0
  238. relaydeck-0.1.0/relaydeck/transports/viewers/print_viewer.py +43 -0
  239. relaydeck-0.1.0/relaydeck/transports/viewers/tmux.py +175 -0
  240. relaydeck-0.1.0/relaydeck/utils/__init__.py +1 -0
  241. relaydeck-0.1.0/relaydeck/vault.py +75 -0
  242. relaydeck-0.1.0/relaydeck/version_check.py +134 -0
  243. relaydeck-0.1.0/relaydeck/web/__init__.py +0 -0
  244. relaydeck-0.1.0/relaydeck/web/static/app.js +1132 -0
  245. relaydeck-0.1.0/relaydeck/web/static/data.js +373 -0
  246. relaydeck-0.1.0/relaydeck/web/static/favicon.svg +10 -0
  247. relaydeck-0.1.0/relaydeck/web/static/fonts/LICENSE +13 -0
  248. relaydeck-0.1.0/relaydeck/web/static/fonts/fonts.css +253 -0
  249. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-300-latin-ext.woff2 +0 -0
  250. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-300-latin.woff2 +0 -0
  251. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-400-latin-ext.woff2 +0 -0
  252. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-400-latin.woff2 +0 -0
  253. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-500-latin-ext.woff2 +0 -0
  254. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-500-latin.woff2 +0 -0
  255. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-600-latin-ext.woff2 +0 -0
  256. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-600-latin.woff2 +0 -0
  257. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-300-latin-ext.woff2 +0 -0
  258. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-300-latin.woff2 +0 -0
  259. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-400-latin-ext.woff2 +0 -0
  260. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-400-latin.woff2 +0 -0
  261. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-500-latin-ext.woff2 +0 -0
  262. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-500-latin.woff2 +0 -0
  263. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-600-latin-ext.woff2 +0 -0
  264. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-600-latin.woff2 +0 -0
  265. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-700-latin-ext.woff2 +0 -0
  266. relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-700-latin.woff2 +0 -0
  267. relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-400-latin-ext.woff2 +0 -0
  268. relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-400-latin.woff2 +0 -0
  269. relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-500-latin-ext.woff2 +0 -0
  270. relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-500-latin.woff2 +0 -0
  271. relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-600-latin-ext.woff2 +0 -0
  272. relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-600-latin.woff2 +0 -0
  273. relaydeck-0.1.0/relaydeck/web/static/harness_brand.js +124 -0
  274. relaydeck-0.1.0/relaydeck/web/static/home.js +1564 -0
  275. relaydeck-0.1.0/relaydeck/web/static/icon_data.js +69 -0
  276. relaydeck-0.1.0/relaydeck/web/static/index.html +35 -0
  277. relaydeck-0.1.0/relaydeck/web/static/lenses/agents.js +582 -0
  278. relaydeck-0.1.0/relaydeck/web/static/lenses/appearance.js +446 -0
  279. relaydeck-0.1.0/relaydeck/web/static/lenses/messages.js +378 -0
  280. relaydeck-0.1.0/relaydeck/web/static/lenses/models.js +1250 -0
  281. relaydeck-0.1.0/relaydeck/web/static/lenses/plugins.js +414 -0
  282. relaydeck-0.1.0/relaydeck/web/static/lenses/workers.js +752 -0
  283. relaydeck-0.1.0/relaydeck/web/static/lenses/workspaces.js +403 -0
  284. relaydeck-0.1.0/relaydeck/web/static/model_select.js +213 -0
  285. relaydeck-0.1.0/relaydeck/web/static/models.css +495 -0
  286. relaydeck-0.1.0/relaydeck/web/static/new_agent.js +1014 -0
  287. relaydeck-0.1.0/relaydeck/web/static/onboarding.js +517 -0
  288. relaydeck-0.1.0/relaydeck/web/static/overlays.js +1540 -0
  289. relaydeck-0.1.0/relaydeck/web/static/panels.css +1394 -0
  290. relaydeck-0.1.0/relaydeck/web/static/primitives.js +288 -0
  291. relaydeck-0.1.0/relaydeck/web/static/shell.js +292 -0
  292. relaydeck-0.1.0/relaydeck/web/static/styles.css +1406 -0
  293. relaydeck-0.1.0/relaydeck/web/static/theme.css +102 -0
  294. relaydeck-0.1.0/relaydeck/web/static/theme.js +91 -0
  295. relaydeck-0.1.0/relaydeck/web/static/tile_system.js +293 -0
  296. relaydeck-0.1.0/relaydeck/web/static/tiles/config.js +70 -0
  297. relaydeck-0.1.0/relaydeck/web/static/tiles/context.js +135 -0
  298. relaydeck-0.1.0/relaydeck/web/static/tiles/events.js +193 -0
  299. relaydeck-0.1.0/relaydeck/web/static/tiles/identity.js +468 -0
  300. relaydeck-0.1.0/relaydeck/web/static/tiles/raw.js +82 -0
  301. relaydeck-0.1.0/relaydeck/web/static/tiles/terminal.js +403 -0
  302. relaydeck-0.1.0/relaydeck/web/static/uikit/README.md +143 -0
  303. relaydeck-0.1.0/relaydeck/web/static/uikit/base.js +225 -0
  304. relaydeck-0.1.0/relaydeck/web/static/uikit/format.js +27 -0
  305. relaydeck-0.1.0/relaydeck/web/static/uikit/index.js +56 -0
  306. relaydeck-0.1.0/relaydeck/web/static/uikit/modal.js +84 -0
  307. relaydeck-0.1.0/relaydeck/web/static/uikit/reactive.js +84 -0
  308. relaydeck-0.1.0/relaydeck/web/static/uikit/settings-form.js +159 -0
  309. relaydeck-0.1.0/relaydeck/web/static/uikit/toggle.js +53 -0
  310. relaydeck-0.1.0/relaydeck/web/static/uikit/uikit.css +78 -0
  311. relaydeck-0.1.0/relaydeck/web/static/uikit/widgets.js +162 -0
  312. relaydeck-0.1.0/relaydeck/web/static/update_banner.js +163 -0
  313. relaydeck-0.1.0/relaydeck/web/static/vendor/lit-all.min.js +116 -0
  314. relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/LICENSE +29 -0
  315. relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/addon-fit.min.js +8 -0
  316. relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/addon-webgl.min.js +8 -0
  317. relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/xterm.min.css +8 -0
  318. relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/xterm.min.js +8 -0
  319. relaydeck-0.1.0/relaydeck/web/static/worker_form.js +414 -0
  320. relaydeck-0.1.0/relaydeck/web/static/workers.css +717 -0
  321. relaydeck-0.1.0/relaydeck/web_runtime.py +47 -0
  322. relaydeck-0.1.0/relaydeck/workers.py +445 -0
  323. relaydeck-0.1.0/relaydeck/workspace_health.py +113 -0
  324. relaydeck-0.1.0/relaydeck/workspace_plugins.py +111 -0
  325. relaydeck-0.1.0/relaydeck/worktrees.py +685 -0
  326. relaydeck-0.1.0/scripts/bump_version.py +96 -0
  327. relaydeck-0.1.0/scripts/gen_web_icons.py +143 -0
  328. relaydeck-0.1.0/scripts/install-behavior.sh +58 -0
  329. relaydeck-0.1.0/scripts/install-smoke.sh +57 -0
  330. relaydeck-0.1.0/scripts/install.sh +176 -0
  331. relaydeck-0.1.0/scripts/test-install.sh +16 -0
  332. relaydeck-0.1.0/scripts/vendor_lit.sh +43 -0
  333. relaydeck-0.1.0/tests/README.md +76 -0
  334. relaydeck-0.1.0/tests/__init__.py +1 -0
  335. relaydeck-0.1.0/tests/conftest.py +121 -0
  336. relaydeck-0.1.0/tests/docker/Dockerfile.base +62 -0
  337. relaydeck-0.1.0/tests/docker/Dockerfile.pi +27 -0
  338. relaydeck-0.1.0/tests/docker/__init__.py +0 -0
  339. relaydeck-0.1.0/tests/docker/compose.yml +42 -0
  340. relaydeck-0.1.0/tests/docker/conftest.py +102 -0
  341. relaydeck-0.1.0/tests/docker/test_zero_bucket.py +219 -0
  342. relaydeck-0.1.0/tests/docker/test_zero_install_scripts.py +54 -0
  343. relaydeck-0.1.0/tests/e2e/__init__.py +0 -0
  344. relaydeck-0.1.0/tests/e2e/_webutil.py +384 -0
  345. relaydeck-0.1.0/tests/e2e/conftest.py +276 -0
  346. relaydeck-0.1.0/tests/e2e/test_cross_harness_messaging_e2e.py +151 -0
  347. relaydeck-0.1.0/tests/e2e/test_harness_integration_e2e.py +379 -0
  348. relaydeck-0.1.0/tests/e2e/test_pi_smoke.py +244 -0
  349. relaydeck-0.1.0/tests/e2e/test_relaydeck_native_smoke.py +67 -0
  350. relaydeck-0.1.0/tests/e2e/test_terminal_image_drop_e2e.py +179 -0
  351. relaydeck-0.1.0/tests/e2e/test_web_harness_e2e.py +178 -0
  352. relaydeck-0.1.0/tests/e2e/test_web_lens_scroll_e2e.py +116 -0
  353. relaydeck-0.1.0/tests/e2e/test_web_lit_regressions_e2e.py +175 -0
  354. relaydeck-0.1.0/tests/e2e/test_web_regression_e2e.py +369 -0
  355. relaydeck-0.1.0/tests/e2e/test_web_relaydeck_native_e2e.py +224 -0
  356. relaydeck-0.1.0/tests/e2e/test_web_settings_onboarding_e2e.py +340 -0
  357. relaydeck-0.1.0/tests/e2e/test_web_telegram_e2e.py +564 -0
  358. relaydeck-0.1.0/tests/e2e/test_web_workers_e2e.py +351 -0
  359. relaydeck-0.1.0/tests/install/Dockerfile +36 -0
  360. relaydeck-0.1.0/tests/test_access_log_filter.py +85 -0
  361. relaydeck-0.1.0/tests/test_agent_edit_editor.py +161 -0
  362. relaydeck-0.1.0/tests/test_agent_events_cli.py +113 -0
  363. relaydeck-0.1.0/tests/test_agent_id_validation.py +127 -0
  364. relaydeck-0.1.0/tests/test_agent_meta.py +418 -0
  365. relaydeck-0.1.0/tests/test_agent_preview_prompt.py +109 -0
  366. relaydeck-0.1.0/tests/test_agent_screen.py +158 -0
  367. relaydeck-0.1.0/tests/test_agent_screen_stopped.py +86 -0
  368. relaydeck-0.1.0/tests/test_agent_stats_accuracy.py +189 -0
  369. relaydeck-0.1.0/tests/test_agent_wait.py +155 -0
  370. relaydeck-0.1.0/tests/test_antigravity_harness.py +210 -0
  371. relaydeck-0.1.0/tests/test_atomicio.py +60 -0
  372. relaydeck-0.1.0/tests/test_attach.py +96 -0
  373. relaydeck-0.1.0/tests/test_audit.py +289 -0
  374. relaydeck-0.1.0/tests/test_auth.py +291 -0
  375. relaydeck-0.1.0/tests/test_auth_tokens.py +328 -0
  376. relaydeck-0.1.0/tests/test_automation_runs.py +575 -0
  377. relaydeck-0.1.0/tests/test_backpressure.py +230 -0
  378. relaydeck-0.1.0/tests/test_bump_version.py +57 -0
  379. relaydeck-0.1.0/tests/test_bundles.py +55 -0
  380. relaydeck-0.1.0/tests/test_bus_durability.py +296 -0
  381. relaydeck-0.1.0/tests/test_claude_code_harness.py +334 -0
  382. relaydeck-0.1.0/tests/test_claude_usage_tailer.py +147 -0
  383. relaydeck-0.1.0/tests/test_cli_cwd_scoping.py +309 -0
  384. relaydeck-0.1.0/tests/test_codex_harness.py +401 -0
  385. relaydeck-0.1.0/tests/test_config.py +264 -0
  386. relaydeck-0.1.0/tests/test_cursor_harness.py +115 -0
  387. relaydeck-0.1.0/tests/test_daemon_bind_host_pref.py +80 -0
  388. relaydeck-0.1.0/tests/test_daemon_lifecycle.py +178 -0
  389. relaydeck-0.1.0/tests/test_daemon_log.py +49 -0
  390. relaydeck-0.1.0/tests/test_dashboard_commands.py +208 -0
  391. relaydeck-0.1.0/tests/test_dashboard_redesign.py +170 -0
  392. relaydeck-0.1.0/tests/test_db.py +429 -0
  393. relaydeck-0.1.0/tests/test_db_maintenance.py +307 -0
  394. relaydeck-0.1.0/tests/test_db_migration.py +83 -0
  395. relaydeck-0.1.0/tests/test_db_pool.py +247 -0
  396. relaydeck-0.1.0/tests/test_external_agents_detector.py +113 -0
  397. relaydeck-0.1.0/tests/test_external_agents_plugin.py +206 -0
  398. relaydeck-0.1.0/tests/test_external_agents_probes.py +99 -0
  399. relaydeck-0.1.0/tests/test_external_agents_store.py +71 -0
  400. relaydeck-0.1.0/tests/test_external_spawn.py +181 -0
  401. relaydeck-0.1.0/tests/test_file_watcher.py +378 -0
  402. relaydeck-0.1.0/tests/test_github_plugin.py +986 -0
  403. relaydeck-0.1.0/tests/test_github_spawn.py +285 -0
  404. relaydeck-0.1.0/tests/test_harness_autonomy.py +243 -0
  405. relaydeck-0.1.0/tests/test_harness_injection_e2e.py +116 -0
  406. relaydeck-0.1.0/tests/test_harness_model.py +172 -0
  407. relaydeck-0.1.0/tests/test_harness_options.py +268 -0
  408. relaydeck-0.1.0/tests/test_harness_plugin_registration.py +77 -0
  409. relaydeck-0.1.0/tests/test_harness_pty.py +90 -0
  410. relaydeck-0.1.0/tests/test_harness_pty_resize.py +128 -0
  411. relaydeck-0.1.0/tests/test_harness_reap.py +123 -0
  412. relaydeck-0.1.0/tests/test_harness_sdk.py +191 -0
  413. relaydeck-0.1.0/tests/test_harness_skill_injection_matrix.py +132 -0
  414. relaydeck-0.1.0/tests/test_hitl.py +235 -0
  415. relaydeck-0.1.0/tests/test_home_widgets_manifest.py +64 -0
  416. relaydeck-0.1.0/tests/test_inbox_stream.py +239 -0
  417. relaydeck-0.1.0/tests/test_install_script.py +104 -0
  418. relaydeck-0.1.0/tests/test_integrations.py +746 -0
  419. relaydeck-0.1.0/tests/test_interactive_prompts.py +527 -0
  420. relaydeck-0.1.0/tests/test_layouts.py +171 -0
  421. relaydeck-0.1.0/tests/test_local_providers.py +143 -0
  422. relaydeck-0.1.0/tests/test_log_privacy.py +103 -0
  423. relaydeck-0.1.0/tests/test_loop_agent.py +463 -0
  424. relaydeck-0.1.0/tests/test_maintenance.py +132 -0
  425. relaydeck-0.1.0/tests/test_messaging.py +1465 -0
  426. relaydeck-0.1.0/tests/test_messaging_durability.py +318 -0
  427. relaydeck-0.1.0/tests/test_messaging_reliability.py +607 -0
  428. relaydeck-0.1.0/tests/test_metering_pricing.py +116 -0
  429. relaydeck-0.1.0/tests/test_model_invocations.py +225 -0
  430. relaydeck-0.1.0/tests/test_model_resolve.py +141 -0
  431. relaydeck-0.1.0/tests/test_model_roles.py +297 -0
  432. relaydeck-0.1.0/tests/test_models_dev.py +307 -0
  433. relaydeck-0.1.0/tests/test_observability.py +348 -0
  434. relaydeck-0.1.0/tests/test_opencode_harness.py +302 -0
  435. relaydeck-0.1.0/tests/test_orchestrator.py +406 -0
  436. relaydeck-0.1.0/tests/test_pi_engine.py +548 -0
  437. relaydeck-0.1.0/tests/test_pi_harness.py +197 -0
  438. relaydeck-0.1.0/tests/test_plugin.py +177 -0
  439. relaydeck-0.1.0/tests/test_plugin_boundary.py +66 -0
  440. relaydeck-0.1.0/tests/test_plugin_disable.py +193 -0
  441. relaydeck-0.1.0/tests/test_plugin_ecosystem_gaps.py +121 -0
  442. relaydeck-0.1.0/tests/test_plugin_platform.py +2324 -0
  443. relaydeck-0.1.0/tests/test_plugin_registry.py +96 -0
  444. relaydeck-0.1.0/tests/test_plugin_scaffold_cli.py +102 -0
  445. relaydeck-0.1.0/tests/test_plugin_settings_g1.py +131 -0
  446. relaydeck-0.1.0/tests/test_plugin_trust_level.py +165 -0
  447. relaydeck-0.1.0/tests/test_preferences.py +90 -0
  448. relaydeck-0.1.0/tests/test_prompt_composition.py +198 -0
  449. relaydeck-0.1.0/tests/test_provider_config.py +256 -0
  450. relaydeck-0.1.0/tests/test_providers.py +285 -0
  451. relaydeck-0.1.0/tests/test_relaydeck_native.py +755 -0
  452. relaydeck-0.1.0/tests/test_relaydeck_native_repl.py +235 -0
  453. relaydeck-0.1.0/tests/test_reply_nudge.py +335 -0
  454. relaydeck-0.1.0/tests/test_runtime_stats.py +63 -0
  455. relaydeck-0.1.0/tests/test_semantic_engine.py +232 -0
  456. relaydeck-0.1.0/tests/test_semantic_status.py +275 -0
  457. relaydeck-0.1.0/tests/test_skills.py +460 -0
  458. relaydeck-0.1.0/tests/test_skills_plugin.py +508 -0
  459. relaydeck-0.1.0/tests/test_static_cache_headers.py +41 -0
  460. relaydeck-0.1.0/tests/test_status_cli.py +297 -0
  461. relaydeck-0.1.0/tests/test_system_prompt.py +373 -0
  462. relaydeck-0.1.0/tests/test_tasks.py +229 -0
  463. relaydeck-0.1.0/tests/test_telegram_commands.py +203 -0
  464. relaydeck-0.1.0/tests/test_telegram_conversation_purge.py +150 -0
  465. relaydeck-0.1.0/tests/test_telegram_plugin.py +1737 -0
  466. relaydeck-0.1.0/tests/test_terminal.py +421 -0
  467. relaydeck-0.1.0/tests/test_terminal_image_upload.py +431 -0
  468. relaydeck-0.1.0/tests/test_testing_helpers.py +144 -0
  469. relaydeck-0.1.0/tests/test_themes.py +433 -0
  470. relaydeck-0.1.0/tests/test_tls.py +234 -0
  471. relaydeck-0.1.0/tests/test_usage_heatmap.py +120 -0
  472. relaydeck-0.1.0/tests/test_usage_limits.py +584 -0
  473. relaydeck-0.1.0/tests/test_vault_encryption.py +274 -0
  474. relaydeck-0.1.0/tests/test_version_check.py +95 -0
  475. relaydeck-0.1.0/tests/test_view.py +274 -0
  476. relaydeck-0.1.0/tests/test_viewers.py +323 -0
  477. relaydeck-0.1.0/tests/test_web_runtime.py +50 -0
  478. relaydeck-0.1.0/tests/test_worker_agent_cleanup.py +172 -0
  479. relaydeck-0.1.0/tests/test_worker_supervision.py +270 -0
  480. relaydeck-0.1.0/tests/test_workers_cli.py +129 -0
  481. relaydeck-0.1.0/tests/test_workspace_api.py +416 -0
  482. relaydeck-0.1.0/tests/test_workspace_cwd_resolution.py +209 -0
  483. relaydeck-0.1.0/tests/test_workspace_health.py +98 -0
  484. relaydeck-0.1.0/tests/test_workspace_view.py +127 -0
  485. relaydeck-0.1.0/tests/test_worktrees.py +713 -0
  486. relaydeck-0.1.0/uv.lock +1937 -0
@@ -0,0 +1,16 @@
1
+ # Keep the install-test build context lean — only the source tree matters
2
+ # (uv builds the wheel from pyproject). Excluding the venv/git/scratch dirs
3
+ # keeps the build fast and reproducible.
4
+ .git
5
+ .venv
6
+ **/__pycache__
7
+ **/*.pyc
8
+ .pytest_cache
9
+ .ruff_cache
10
+ .playwright-mcp
11
+ node_modules
12
+ *.png
13
+ .claude
14
+ dist
15
+ build
16
+ *.egg-info
@@ -0,0 +1,19 @@
1
+ # GitHub handles approved to bypass the contribution auto-close gate.
2
+ #
3
+ # Format: <username> <capability>
4
+ # issue their future ISSUES stay open
5
+ # pr their future ISSUES *and* PRs stay open
6
+ #
7
+ # Repository collaborators (write / maintain / admin) are ALWAYS exempt and do
8
+ # not need to be listed here — the gate checks collaborator permission first.
9
+ #
10
+ # Default maintainers (pre-approved for issues + PRs):
11
+ relaydeck pr
12
+ #
13
+ # Maintainers grant access to others by replying on an issue:
14
+ # `lgtmi` -> adds the issue author with capability `issue`
15
+ # `lgtm` -> adds the issue author with capability `pr`
16
+ # The approve-contributor workflow appends the entry below automatically.
17
+ #
18
+ # One entry per line, e.g.:
19
+ # octocat pr
@@ -0,0 +1,67 @@
1
+ name: Bug report
2
+ description: Report something in relaydeck that's broken
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ **Before you start:** read [CONTRIBUTING.md](https://github.com/relaydeck/relaydeck/blob/main/CONTRIBUTING.md).
9
+
10
+ New issues from first-time contributors are auto-closed by default. Maintainers review auto-closed issues and reopen the worthwhile ones. Issues that don't meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.
11
+
12
+ Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
13
+
14
+ - type: textarea
15
+ id: what
16
+ attributes:
17
+ label: What happened?
18
+ description: Be specific. Include the exact error / log output if any.
19
+ validations:
20
+ required: true
21
+
22
+ - type: textarea
23
+ id: repro
24
+ attributes:
25
+ label: Steps to reproduce
26
+ description: Minimal steps that trigger the bug.
27
+ validations:
28
+ required: true
29
+
30
+ - type: textarea
31
+ id: expected
32
+ attributes:
33
+ label: Expected behavior
34
+ validations:
35
+ required: false
36
+
37
+ - type: input
38
+ id: version
39
+ attributes:
40
+ label: relaydeck version
41
+ description: Output of `relaydeck --version` (e.g. 0.1.0).
42
+ validations:
43
+ required: false
44
+
45
+ - type: dropdown
46
+ id: harness
47
+ attributes:
48
+ label: Harness involved (if any)
49
+ options:
50
+ - "Not harness-specific"
51
+ - "pi / relaydeck-native"
52
+ - "Claude Code"
53
+ - "Codex CLI"
54
+ - "Cursor CLI"
55
+ - "OpenCode"
56
+ - "Antigravity"
57
+ - "Other"
58
+ validations:
59
+ required: false
60
+
61
+ - type: input
62
+ id: os
63
+ attributes:
64
+ label: OS
65
+ description: e.g. macOS 15.4, Ubuntu 24.04.
66
+ validations:
67
+ required: false
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Questions & ideas
4
+ url: https://github.com/relaydeck/relaydeck/discussions
5
+ about: Ask questions or float ideas in Discussions instead of opening an issue.
6
+ - name: Security report
7
+ url: https://github.com/relaydeck/relaydeck/security/advisories/new
8
+ about: Report a vulnerability privately (see SECURITY.md) — do not open a public issue.
@@ -0,0 +1,46 @@
1
+ name: Change / feature proposal
2
+ description: Propose a change or feature (required for first-time contributors before opening a PR)
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ **Before you start:** read [CONTRIBUTING.md](https://github.com/relaydeck/relaydeck/blob/main/CONTRIBUTING.md).
9
+
10
+ New issues from first-time contributors are auto-closed by default. Maintainers review auto-closed issues and reopen the worthwhile ones. Issues that don't meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.
11
+
12
+ Open a proposal **before** sending a PR — PRs from contributors who haven't been approved with `lgtm` are auto-closed.
13
+
14
+ Keep this short. If it doesn't fit on one screen, it's too long. Write in your own voice.
15
+
16
+ - type: textarea
17
+ id: what
18
+ attributes:
19
+ label: What do you want to change?
20
+ description: Be specific and concise.
21
+ validations:
22
+ required: true
23
+
24
+ - type: textarea
25
+ id: why
26
+ attributes:
27
+ label: Why?
28
+ description: What problem does this solve? Who is it for?
29
+ validations:
30
+ required: true
31
+
32
+ - type: textarea
33
+ id: how
34
+ attributes:
35
+ label: How? (optional)
36
+ description: Brief technical approach if you have one in mind. Note if it's a plugin vs. a core change — relaydeck keeps its core minimal and pushes features into plugins.
37
+ validations:
38
+ required: false
39
+
40
+ - type: checkboxes
41
+ id: implement
42
+ attributes:
43
+ label: Implementation
44
+ options:
45
+ - label: I'd like to implement this myself if approved
46
+ required: false
@@ -0,0 +1,29 @@
1
+ version: 2
2
+ updates:
3
+ # Keep GitHub Actions pinned-but-fresh. Security-relevant for the
4
+ # pull_request_target gate + the OIDC publish workflow. Grouped so all
5
+ # action bumps arrive as a single PR (one commit) rather than one per action.
6
+ - package-ecosystem: "github-actions"
7
+ directory: "/"
8
+ schedule:
9
+ interval: "weekly"
10
+ open-pull-requests-limit: 5
11
+ labels: ["dependencies"]
12
+ commit-message:
13
+ prefix: "chore(actions)"
14
+ groups:
15
+ github-actions:
16
+ patterns: ["*"]
17
+
18
+ # Python dependencies declared in pyproject.toml. Grouped into one PR.
19
+ - package-ecosystem: "pip"
20
+ directory: "/"
21
+ schedule:
22
+ interval: "weekly"
23
+ open-pull-requests-limit: 5
24
+ labels: ["dependencies"]
25
+ commit-message:
26
+ prefix: "chore(deps)"
27
+ groups:
28
+ python:
29
+ patterns: ["*"]
@@ -0,0 +1,30 @@
1
+ <!--
2
+ Before opening a PR, read CONTRIBUTING.md.
3
+
4
+ PRs from contributors who haven't been approved with `lgtm` on an issue are
5
+ auto-closed. Open a proposal issue first, get `lgtm`, then send the PR.
6
+
7
+ The one rule: you must understand your code. Using AI to write it is fine;
8
+ submitting code you can't explain is not.
9
+ -->
10
+
11
+ ## What & why
12
+
13
+ <!-- What does this change and why? Link the approved issue: Closes #NNN -->
14
+
15
+ Closes #
16
+
17
+ ## How
18
+
19
+ <!-- Brief technical summary. If this adds a capability, did you ship the web
20
+ affordance too? (The dashboard is the primary interface; the CLI is at
21
+ parity, not ahead.) -->
22
+
23
+ ## Checklist
24
+
25
+ - [ ] I understand this code and can explain how it works.
26
+ - [ ] I opened a proposal issue and a maintainer replied `lgtm`.
27
+ - [ ] Tests added/updated; `uv run pytest -q -m "not e2e"` is green locally.
28
+ - [ ] `uv run relaydeck plugin verify` passes (if plugins/manifests changed).
29
+ - [ ] New CLI capability ships its web affordance in the same PR (parity).
30
+ - [ ] I did **not** edit `CHANGELOG.md` (maintainers curate it) unless asked.
@@ -0,0 +1,117 @@
1
+ name: Approve Contributor
2
+
3
+ # A maintainer comment of `lgtmi` (issues) or `lgtm` (issues + PRs) on an issue
4
+ # adds that issue's author to .github/APPROVED_CONTRIBUTORS so the gates stop
5
+ # auto-closing their submissions.
6
+ #
7
+ # Adapted, with thanks, from the pi project (earendil-works/pi).
8
+
9
+ on:
10
+ issue_comment:
11
+ types: [created]
12
+
13
+ permissions:
14
+ contents: write
15
+ issues: write
16
+
17
+ jobs:
18
+ approve:
19
+ if: ${{ !github.event.issue.pull_request }}
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@v6
24
+ with:
25
+ ref: ${{ github.event.repository.default_branch }}
26
+
27
+ - name: Update contributor approval
28
+ id: update
29
+ uses: actions/github-script@v9
30
+ with:
31
+ script: |
32
+ const fs = require('fs');
33
+ const APPROVED_FILE = '.github/APPROVED_CONTRIBUTORS';
34
+ const VALID_CAPABILITIES = new Set(['issue', 'pr']);
35
+ const issueAuthor = context.payload.issue.user.login;
36
+ const commenter = context.payload.comment.user.login;
37
+ const body = (context.payload.comment.body || '').trim();
38
+
39
+ let target;
40
+ if (/\blgtmi\b/i.test(body)) target = 'issue';
41
+ else if (/\blgtm\b/i.test(body)) target = 'pr';
42
+ else { core.setOutput('status', 'skipped'); return; }
43
+
44
+ try {
45
+ const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
46
+ owner: context.repo.owner, repo: context.repo.repo, username: commenter,
47
+ });
48
+ if (!['admin', 'maintain', 'write'].includes(data.permission)) {
49
+ console.log(`${commenter} lacks write access`);
50
+ core.setOutput('status', 'skipped'); return;
51
+ }
52
+ } catch {
53
+ core.setOutput('status', 'skipped'); return;
54
+ }
55
+
56
+ function parse(content) {
57
+ const entries = [];
58
+ const users = new Map();
59
+ for (const line of content.split('\n')) {
60
+ const t = line.trim();
61
+ if (!t || t.startsWith('#')) { entries.push({ type: 'other', line }); continue; }
62
+ const parts = t.split(/\s+/);
63
+ if (parts.length !== 2 || !VALID_CAPABILITIES.has(parts[1].toLowerCase())) {
64
+ entries.push({ type: 'other', line }); continue;
65
+ }
66
+ const entry = { type: 'user', username: parts[0], normalizedUser: parts[0].toLowerCase(), capability: parts[1].toLowerCase() };
67
+ entries.push(entry);
68
+ users.set(entry.normalizedUser, entry);
69
+ }
70
+ return { entries, users };
71
+ }
72
+
73
+ function stringify(entries) {
74
+ const out = [...entries];
75
+ while (out.length && out[out.length - 1].type === 'other' && out[out.length - 1].line.trim() === '') out.pop();
76
+ return out.map(e => e.type === 'user' ? `${e.username} ${e.capability}` : e.line).join('\n') + '\n';
77
+ }
78
+
79
+ const { entries, users } = parse(fs.readFileSync(APPROVED_FILE, 'utf8'));
80
+ const existing = users.get(issueAuthor.toLowerCase());
81
+ const existingCap = existing?.capability ?? null;
82
+
83
+ if (existingCap === 'pr' || existingCap === target) {
84
+ core.setOutput('status', 'already'); core.setOutput('capability', existingCap); return;
85
+ }
86
+ if (existing) existing.capability = target;
87
+ else entries.push({ type: 'user', username: issueAuthor, normalizedUser: issueAuthor.toLowerCase(), capability: target });
88
+
89
+ fs.writeFileSync(APPROVED_FILE, stringify(entries));
90
+ core.setOutput('status', existingCap ? 'updated' : 'added');
91
+ core.setOutput('capability', target);
92
+
93
+ - name: Commit and push
94
+ if: steps.update.outputs.status == 'added' || steps.update.outputs.status == 'updated'
95
+ run: |
96
+ git config user.name "github-actions[bot]"
97
+ git config user.email "github-actions[bot]@users.noreply.github.com"
98
+ git add .github/APPROVED_CONTRIBUTORS
99
+ git diff --staged --quiet || git commit -m "chore: approve contributor ${{ github.event.issue.user.login }}"
100
+ git push
101
+
102
+ - name: Comment on issue
103
+ if: steps.update.outputs.status != 'skipped'
104
+ uses: actions/github-script@v9
105
+ with:
106
+ script: |
107
+ const author = context.payload.issue.user.login;
108
+ const cap = '${{ steps.update.outputs.capability }}';
109
+ const status = '${{ steps.update.outputs.status }}';
110
+ let body;
111
+ if (status === 'already') body = `@${author} is already approved.`;
112
+ else if (cap === 'issue') body = `@${author} approved for issues — your future issues won't be auto-closed. PRs still need \`lgtm\`.`;
113
+ else body = `@${author} approved for issues and PRs — welcome, and thanks for contributing.`;
114
+ await github.rest.issues.createComment({
115
+ owner: context.repo.owner, repo: context.repo.repo,
116
+ issue_number: context.issue.number, body,
117
+ });
@@ -0,0 +1,134 @@
1
+ name: ci
2
+
3
+ on:
4
+ # Gate runs before a PR merges. With rebase-only + required status checks,
5
+ # this covers main without also double-running on every push to it.
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ # Cancel any superseded run for the same ref so a fast follow-up
11
+ # push doesn't pile a long queue.
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ name: pytest + plugin verify
19
+ runs-on: ubuntu-latest
20
+ timeout-minutes: 10
21
+ steps:
22
+ - uses: actions/checkout@v6
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v3
26
+ with:
27
+ version: "latest"
28
+ # Cache uv's wheel cache so subsequent runs avoid the cold
29
+ # download of fastapi/uvicorn/torch-adjacent deps.
30
+ enable-cache: true
31
+ cache-dependency-glob: "uv.lock"
32
+
33
+ - name: Set up Python
34
+ run: uv python install 3.12
35
+
36
+ - name: Install project + dev deps
37
+ run: uv sync --frozen
38
+
39
+ - name: Run test suite
40
+ # Single source of truth. Auth tests, durability tests, and
41
+ # the usage-limits showcase plugin all live in tests/.
42
+ # Excludes `e2e`: those need a real harness binary + LLM API
43
+ # key and run in the dedicated `e2e` workflow.
44
+ run: uv run pytest -q -m "not e2e"
45
+
46
+ - name: Verify plugin manifests + lockfile
47
+ # `relaydeck plugin verify` parses every plugin.toml and writes the
48
+ # plugins.lock baseline. CI runs it as a smoke check — if the
49
+ # set of manifest-backed plugins diverges from what the loader
50
+ # accepts, this command exits non-zero before downstream tests
51
+ # have a chance to mask the regression.
52
+ run: uv run relaydeck plugin verify
53
+
54
+ - name: Daemon smoke test
55
+ # Boot the daemon, hit /healthz (public), hit /api/agents with
56
+ # the on-disk token (authenticated), then tear down. Catches
57
+ # regressions in the auth middleware, the token bootstrap, and
58
+ # the basic API wiring even when unit tests still pass.
59
+ run: |
60
+ set -euo pipefail
61
+ export RELAYDECK_CONFIG_HOME=$RUNNER_TEMP/relaydeck-cfg
62
+ mkdir -p "$RELAYDECK_CONFIG_HOME"
63
+ uv run relaydeck serve --port 8765 &
64
+ DAEMON_PID=$!
65
+ # Wait up to 15s for /healthz to come up.
66
+ for i in $(seq 1 30); do
67
+ if curl -sf http://127.0.0.1:8765/healthz >/dev/null; then
68
+ break
69
+ fi
70
+ sleep 0.5
71
+ done
72
+ curl -sf http://127.0.0.1:8765/healthz
73
+ # An unauthenticated /api/agents must 401.
74
+ code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/api/agents)
75
+ [ "$code" = "401" ] || { echo "expected 401 without token, got $code"; exit 1; }
76
+ # With the token, it must 200.
77
+ TOKEN=$(cat "$HOME/.relaydeck/auth-token")
78
+ curl -sf -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8765/api/agents >/dev/null
79
+ kill $DAEMON_PID
80
+
81
+ lint:
82
+ name: ruff
83
+ runs-on: ubuntu-latest
84
+ timeout-minutes: 3
85
+ steps:
86
+ - uses: actions/checkout@v6
87
+
88
+ - name: Install uv
89
+ uses: astral-sh/setup-uv@v3
90
+ with:
91
+ version: "latest"
92
+ enable-cache: true
93
+ cache-dependency-glob: "uv.lock"
94
+
95
+ - name: Set up Python
96
+ run: uv python install 3.12
97
+
98
+ - name: Install dev deps
99
+ # Use the project's locked ruff (in dev deps) so CI and local
100
+ # runs see the same version. `uv sync` includes dev by default.
101
+ run: uv sync --frozen
102
+
103
+ - name: Ruff check (soft)
104
+ # CI lints with `--exit-zero` for now: the codebase has known
105
+ # style debt unrelated to the platform foundation work, and we
106
+ # don't want green-tests-but-red-CI noise. Once the catalog is
107
+ # cleaned up, drop --exit-zero and treat lint as a gate.
108
+ run: uv run ruff check relaydeck tests --exit-zero
109
+
110
+ build:
111
+ name: build (sdist + wheel)
112
+ runs-on: ubuntu-latest
113
+ timeout-minutes: 6
114
+ steps:
115
+ - uses: actions/checkout@v6
116
+
117
+ - name: Install uv
118
+ uses: astral-sh/setup-uv@v3
119
+ with:
120
+ version: "latest"
121
+ enable-cache: true
122
+ cache-dependency-glob: "uv.lock"
123
+
124
+ - name: Set up Python
125
+ run: uv python install 3.12
126
+
127
+ - name: Build sdist + wheel
128
+ # Pre-release insurance: catches packaging regressions (missing package
129
+ # data, bad metadata, a wheel that doesn't include plugins/) on every PR
130
+ # instead of at `release.yml` publish time.
131
+ run: uv build
132
+
133
+ - name: Validate distribution metadata
134
+ run: uvx twine check dist/*
@@ -0,0 +1,59 @@
1
+ name: docker-fast
2
+
3
+ # PR fast lane for Docker-based bucket tests. Phase 1 runs B1 (zero) only;
4
+ # Phase 2 adds B2 (pi-only). Both buckets in parallel, ≤10 min budget.
5
+ #
6
+ # Supersedes the previous install.yml workflow (which only built the slim
7
+ # install image and ran scripts/install-smoke.sh). B1 covers everything
8
+ # install.yml did plus the doctor-honesty and degradation assertions.
9
+ #
10
+ # Nightly full-matrix coverage (B3 onward) lands in a separate docker-full
11
+ # workflow in Phase 4.
12
+
13
+ on:
14
+ pull_request:
15
+ branches: [main, master]
16
+ workflow_dispatch:
17
+
18
+ concurrency:
19
+ group: ${{ github.workflow }}-${{ github.ref }}
20
+ cancel-in-progress: true
21
+
22
+ jobs:
23
+ bucket:
24
+ name: docker / B${{ matrix.bucket }}
25
+ runs-on: ubuntu-latest
26
+ timeout-minutes: 10
27
+ strategy:
28
+ fail-fast: false
29
+ matrix:
30
+ # Phase 1: B1 (zero) only. Phase 2 appends:
31
+ # - { bucket: 2, name: pi-only, image: pi, dockerfile: Dockerfile.pi }
32
+ include:
33
+ - bucket: 1
34
+ name: zero
35
+ image: base
36
+ dockerfile: Dockerfile.base
37
+ steps:
38
+ - uses: actions/checkout@v6
39
+
40
+ - name: Build relaydeck-test:${{ matrix.image }}
41
+ run: |
42
+ docker build \
43
+ -f tests/docker/${{ matrix.dockerfile }} \
44
+ -t relaydeck-test:${{ matrix.image }} \
45
+ .
46
+
47
+ - name: Run docker tests (B${{ matrix.bucket }} / ${{ matrix.name }})
48
+ run: |
49
+ docker run --rm \
50
+ -e RELAYDECK_TEST_BUCKET=${{ matrix.name }} \
51
+ relaydeck-test:${{ matrix.image }} \
52
+ pytest -m docker --confcutdir=/src/tests/docker -c /src/pyproject.toml -o addopts= -p no:cacheprovider /src/tests/docker/ -v --junitxml=/tmp/junit.xml || RC=$?
53
+ exit ${RC:-0}
54
+
55
+ # If pytest fails, the JUnit XML and the daemon log are useful artifacts
56
+ # for diagnosis. Docker doesn't preserve files after `--rm` finishes,
57
+ # so the test must have written them to a host-mounted volume; Phase 1
58
+ # keeps the simple path and re-runs locally with `make test-docker` for
59
+ # failure triage. Phase 2 wires a proper /tmp/junit mount + upload-artifact.
@@ -0,0 +1,77 @@
1
+ name: e2e
2
+
3
+ # Runs the `e2e` pytest marker against real harness binaries + a real
4
+ # LLM endpoint. Kept in a dedicated workflow so the fast unit-test CI
5
+ # stays free of API latency + cost.
6
+ #
7
+ # Triggers:
8
+ # - pull_request to main: end-to-end smoke gate before merge
9
+ # - workflow_dispatch: manual re-run when investigating a regression
10
+ #
11
+ # Cost ceiling: the smoke test issues a single short prompt to the
12
+ # cheapest free-tier model on OpenRouter. Concurrency cancels stacked
13
+ # runs so a fast follow-up push doesn't queue. Job timeout is 5 min.
14
+
15
+ on:
16
+ pull_request:
17
+ branches: [main]
18
+ workflow_dispatch:
19
+
20
+ concurrency:
21
+ group: ${{ github.workflow }}-${{ github.ref }}
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ pi-smoke:
26
+ name: pytest -m e2e (pi)
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 5
29
+ # Skip silently when the secret is missing -- e.g. on a fork PR or
30
+ # a workflow_dispatch run from a contributor without org access.
31
+ # The job appears as 'skipped' in the UI rather than 'failed'.
32
+ # Gated on the org owner so it runs on the canonical repo and still
33
+ # skips on forks (which won't have the OPENROUTER_API_KEY secret).
34
+ if: ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'relaydeck' }}
35
+ steps:
36
+ - uses: actions/checkout@v6
37
+
38
+ - name: Install uv
39
+ uses: astral-sh/setup-uv@v3
40
+ with:
41
+ version: "latest"
42
+ enable-cache: true
43
+ cache-dependency-glob: "uv.lock"
44
+
45
+ - name: Set up Python
46
+ run: uv python install 3.12
47
+
48
+ - name: Install project + dev deps
49
+ run: uv sync --frozen
50
+
51
+ - name: Install pi (npm)
52
+ # @mariozechner/pi-coding-agent installs the `pi` binary into
53
+ # the npm-global bin dir. Pinning to a specific version would
54
+ # make the test reproducible -- left floating for now so we
55
+ # notice when upstream changes the CLI surface.
56
+ run: |
57
+ npm install -g @mariozechner/pi-coding-agent
58
+ pi --help | head -3
59
+
60
+ - name: Run E2E suite
61
+ env:
62
+ OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
63
+ # Pi reads the API key from this env var by default when
64
+ # `--provider openrouter` is set.
65
+ # Model slug is read from the repo-level Actions variable
66
+ # `RELAYDECK_E2E_MODEL` so it can be swapped without code changes
67
+ # (Settings -> Secrets and variables -> Actions -> Variables).
68
+ # Fallback covers the case where the variable hasn't been set
69
+ # yet -- pick something currently reachable on openrouter.
70
+ RELAYDECK_E2E_MODEL: ${{ vars.RELAYDECK_E2E_MODEL || 'openai/gpt-4o-mini' }}
71
+ RELAYDECK_E2E_HEADLESS: "1"
72
+ run: |
73
+ if [ -z "${OPENROUTER_API_KEY:-}" ]; then
74
+ echo "::warning::OPENROUTER_API_KEY not set; skipping e2e suite"
75
+ exit 0
76
+ fi
77
+ uv run pytest -v -m e2e --tb=short