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.
- relaydeck-0.1.0/.dockerignore +16 -0
- relaydeck-0.1.0/.github/APPROVED_CONTRIBUTORS +19 -0
- relaydeck-0.1.0/.github/ISSUE_TEMPLATE/bug.yml +67 -0
- relaydeck-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- relaydeck-0.1.0/.github/ISSUE_TEMPLATE/feature.yml +46 -0
- relaydeck-0.1.0/.github/dependabot.yml +29 -0
- relaydeck-0.1.0/.github/pull_request_template.md +30 -0
- relaydeck-0.1.0/.github/workflows/approve-contributor.yml +117 -0
- relaydeck-0.1.0/.github/workflows/ci.yml +134 -0
- relaydeck-0.1.0/.github/workflows/docker-fast.yml +59 -0
- relaydeck-0.1.0/.github/workflows/e2e.yml +77 -0
- relaydeck-0.1.0/.github/workflows/issue-gate.yml +110 -0
- relaydeck-0.1.0/.github/workflows/pr-gate.yml +108 -0
- relaydeck-0.1.0/.github/workflows/release.yml +85 -0
- relaydeck-0.1.0/.github/workflows/version-bump.yml +60 -0
- relaydeck-0.1.0/.gitignore +58 -0
- relaydeck-0.1.0/AGENTS.md +555 -0
- relaydeck-0.1.0/CHANGELOG.md +89 -0
- relaydeck-0.1.0/CONTRIBUTING.md +137 -0
- relaydeck-0.1.0/CREDITS.md +99 -0
- relaydeck-0.1.0/LICENSE +21 -0
- relaydeck-0.1.0/Makefile +106 -0
- relaydeck-0.1.0/PKG-INFO +335 -0
- relaydeck-0.1.0/README.md +302 -0
- relaydeck-0.1.0/SECURITY.md +32 -0
- relaydeck-0.1.0/TESTING.md +208 -0
- relaydeck-0.1.0/docs/RELEASE.md +79 -0
- relaydeck-0.1.0/docs/playwright.md +389 -0
- relaydeck-0.1.0/plugins/__init__.py +19 -0
- relaydeck-0.1.0/plugins/bundle.toml +30 -0
- relaydeck-0.1.0/plugins/dashboard/SKILL.md +66 -0
- relaydeck-0.1.0/plugins/dashboard/__init__.py +1 -0
- relaydeck-0.1.0/plugins/dashboard/plugin.py +69 -0
- relaydeck-0.1.0/plugins/dashboard/plugin.toml +21 -0
- relaydeck-0.1.0/plugins/external_agents/__init__.py +2 -0
- relaydeck-0.1.0/plugins/external_agents/detector.py +223 -0
- relaydeck-0.1.0/plugins/external_agents/harness.py +83 -0
- relaydeck-0.1.0/plugins/external_agents/models.py +183 -0
- relaydeck-0.1.0/plugins/external_agents/plugin.py +640 -0
- relaydeck-0.1.0/plugins/external_agents/plugin.toml +30 -0
- relaydeck-0.1.0/plugins/external_agents/probes.py +165 -0
- relaydeck-0.1.0/plugins/external_agents/static/panel.js +365 -0
- relaydeck-0.1.0/plugins/external_agents/store.py +97 -0
- relaydeck-0.1.0/plugins/file_watcher/__init__.py +0 -0
- relaydeck-0.1.0/plugins/file_watcher/plugin.py +341 -0
- relaydeck-0.1.0/plugins/file_watcher/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/gateway/__init__.py +0 -0
- relaydeck-0.1.0/plugins/gateway/plugin.py +218 -0
- relaydeck-0.1.0/plugins/gateway/plugin.toml +15 -0
- relaydeck-0.1.0/plugins/github/__init__.py +0 -0
- relaydeck-0.1.0/plugins/github/enrich.py +135 -0
- relaydeck-0.1.0/plugins/github/plugin.py +912 -0
- relaydeck-0.1.0/plugins/github/plugin.toml +50 -0
- relaydeck-0.1.0/plugins/github/poller.py +447 -0
- relaydeck-0.1.0/plugins/github/rules.py +302 -0
- relaydeck-0.1.0/plugins/github/spawn.py +151 -0
- relaydeck-0.1.0/plugins/github/static/panel.js +1440 -0
- relaydeck-0.1.0/plugins/harnesses/__init__.py +1 -0
- relaydeck-0.1.0/plugins/harnesses/antigravity/__init__.py +1 -0
- relaydeck-0.1.0/plugins/harnesses/antigravity/agent.py +302 -0
- relaydeck-0.1.0/plugins/harnesses/antigravity/plugin.py +17 -0
- relaydeck-0.1.0/plugins/harnesses/antigravity/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/harnesses/claude_code/__init__.py +0 -0
- relaydeck-0.1.0/plugins/harnesses/claude_code/agent.py +471 -0
- relaydeck-0.1.0/plugins/harnesses/claude_code/plugin.py +23 -0
- relaydeck-0.1.0/plugins/harnesses/claude_code/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/harnesses/codex/__init__.py +0 -0
- relaydeck-0.1.0/plugins/harnesses/codex/agent.py +613 -0
- relaydeck-0.1.0/plugins/harnesses/codex/plugin.py +17 -0
- relaydeck-0.1.0/plugins/harnesses/codex/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/harnesses/cursor/__init__.py +1 -0
- relaydeck-0.1.0/plugins/harnesses/cursor/agent.py +390 -0
- relaydeck-0.1.0/plugins/harnesses/cursor/plugin.py +18 -0
- relaydeck-0.1.0/plugins/harnesses/cursor/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/harnesses/opencode/__init__.py +0 -0
- relaydeck-0.1.0/plugins/harnesses/opencode/agent.py +394 -0
- relaydeck-0.1.0/plugins/harnesses/opencode/plugin.py +19 -0
- relaydeck-0.1.0/plugins/harnesses/opencode/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/harnesses/pi/__init__.py +0 -0
- relaydeck-0.1.0/plugins/harnesses/pi/agent.py +390 -0
- relaydeck-0.1.0/plugins/harnesses/pi/plugin.py +56 -0
- relaydeck-0.1.0/plugins/harnesses/pi/plugin.toml +17 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/__init__.py +0 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/agent.py +365 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/pi_engine.py +930 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/pi_extension.ts +186 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/pi_startup.ts +210 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/plugin.py +135 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/plugin.toml +24 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/prompt.py +255 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/calls.js +111 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/context.js +109 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/pi_install.js +183 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/static/widget_chat.js +235 -0
- relaydeck-0.1.0/plugins/harnesses/relaydeck_native/tools.py +405 -0
- relaydeck-0.1.0/plugins/hitl/__init__.py +1 -0
- relaydeck-0.1.0/plugins/hitl/plugin.py +389 -0
- relaydeck-0.1.0/plugins/hitl/plugin.toml +27 -0
- relaydeck-0.1.0/plugins/loop/__init__.py +0 -0
- relaydeck-0.1.0/plugins/loop/agent.py +415 -0
- relaydeck-0.1.0/plugins/loop/plugin.py +51 -0
- relaydeck-0.1.0/plugins/loop/plugin.toml +13 -0
- relaydeck-0.1.0/plugins/messaging/SKILL.md +133 -0
- relaydeck-0.1.0/plugins/messaging/__init__.py +0 -0
- relaydeck-0.1.0/plugins/messaging/plugin.py +1403 -0
- relaydeck-0.1.0/plugins/messaging/plugin.toml +45 -0
- relaydeck-0.1.0/plugins/messaging/static/tile_compose.js +108 -0
- relaydeck-0.1.0/plugins/messaging/static/tile_inbox.js +253 -0
- relaydeck-0.1.0/plugins/metering/__init__.py +0 -0
- relaydeck-0.1.0/plugins/metering/plugin.py +354 -0
- relaydeck-0.1.0/plugins/metering/plugin.toml +25 -0
- relaydeck-0.1.0/plugins/metering/static/fleet.js +191 -0
- relaydeck-0.1.0/plugins/metering/static/tile_cost.js +86 -0
- relaydeck-0.1.0/plugins/metering/static/tile_tokens.js +95 -0
- relaydeck-0.1.0/plugins/prompts/SKILL.md +74 -0
- relaydeck-0.1.0/plugins/prompts/__init__.py +1 -0
- relaydeck-0.1.0/plugins/prompts/plugin.py +465 -0
- relaydeck-0.1.0/plugins/prompts/plugin.toml +64 -0
- relaydeck-0.1.0/plugins/prompts/static/tile_prompts.js +113 -0
- relaydeck-0.1.0/plugins/providers/__init__.py +0 -0
- relaydeck-0.1.0/plugins/providers/anthropic/__init__.py +0 -0
- relaydeck-0.1.0/plugins/providers/anthropic/plugin.py +109 -0
- relaydeck-0.1.0/plugins/providers/anthropic/plugin.toml +10 -0
- relaydeck-0.1.0/plugins/providers/ollama/__init__.py +0 -0
- relaydeck-0.1.0/plugins/providers/ollama/plugin.py +12 -0
- relaydeck-0.1.0/plugins/providers/ollama/plugin.toml +9 -0
- relaydeck-0.1.0/plugins/providers/openai/__init__.py +0 -0
- relaydeck-0.1.0/plugins/providers/openai/plugin.py +100 -0
- relaydeck-0.1.0/plugins/providers/openai/plugin.toml +10 -0
- relaydeck-0.1.0/plugins/providers/openrouter/__init__.py +0 -0
- relaydeck-0.1.0/plugins/providers/openrouter/plugin.py +224 -0
- relaydeck-0.1.0/plugins/providers/openrouter/plugin.toml +10 -0
- relaydeck-0.1.0/plugins/py.typed +1 -0
- relaydeck-0.1.0/plugins/registry.yaml +43 -0
- relaydeck-0.1.0/plugins/skills/FLEET_SKILL.md +62 -0
- relaydeck-0.1.0/plugins/skills/PLUGIN_AUTHORING_SKILL.md +215 -0
- relaydeck-0.1.0/plugins/skills/__init__.py +0 -0
- relaydeck-0.1.0/plugins/skills/commands.py +203 -0
- relaydeck-0.1.0/plugins/skills/manager.py +295 -0
- relaydeck-0.1.0/plugins/skills/plugin.py +204 -0
- relaydeck-0.1.0/plugins/skills/plugin.toml +44 -0
- relaydeck-0.1.0/plugins/skills/routes.py +121 -0
- relaydeck-0.1.0/plugins/skills/static/panel.js +374 -0
- relaydeck-0.1.0/plugins/telegram/SKILL.md +169 -0
- relaydeck-0.1.0/plugins/telegram/__init__.py +0 -0
- relaydeck-0.1.0/plugins/telegram/conversations.py +188 -0
- relaydeck-0.1.0/plugins/telegram/inbound_map.py +123 -0
- relaydeck-0.1.0/plugins/telegram/plugin.py +2421 -0
- relaydeck-0.1.0/plugins/telegram/plugin.toml +112 -0
- relaydeck-0.1.0/plugins/telegram/routes.py +378 -0
- relaydeck-0.1.0/plugins/telegram/static/conversations.js +71 -0
- relaydeck-0.1.0/plugins/telegram/static/panel.js +1487 -0
- relaydeck-0.1.0/plugins/telegram/static/tile_chats.js +107 -0
- relaydeck-0.1.0/plugins/telegram/typing_sessions.py +132 -0
- relaydeck-0.1.0/plugins/telegram/worker.py +600 -0
- relaydeck-0.1.0/plugins/theme/SKILL.md +70 -0
- relaydeck-0.1.0/plugins/theme/__init__.py +1 -0
- relaydeck-0.1.0/plugins/theme/plugin.py +75 -0
- relaydeck-0.1.0/plugins/theme/plugin.toml +21 -0
- relaydeck-0.1.0/plugins/usage_limits/__init__.py +0 -0
- relaydeck-0.1.0/plugins/usage_limits/core.py +153 -0
- relaydeck-0.1.0/plugins/usage_limits/plugin.py +469 -0
- relaydeck-0.1.0/plugins/usage_limits/plugin.toml +43 -0
- relaydeck-0.1.0/plugins/usage_limits/static/panel.js +135 -0
- relaydeck-0.1.0/plugins/usage_limits/static/tile.js +105 -0
- relaydeck-0.1.0/plugins/vault/__init__.py +0 -0
- relaydeck-0.1.0/plugins/vault/plugin.py +518 -0
- relaydeck-0.1.0/plugins/vault/plugin.toml +24 -0
- relaydeck-0.1.0/plugins/vault/static/vault.js +171 -0
- relaydeck-0.1.0/plugins/vault/store.py +338 -0
- relaydeck-0.1.0/pyproject.toml +106 -0
- relaydeck-0.1.0/relaydeck/__init__.py +55 -0
- relaydeck-0.1.0/relaydeck/__main__.py +8 -0
- relaydeck-0.1.0/relaydeck/agents_base.py +108 -0
- relaydeck-0.1.0/relaydeck/atomicio.py +37 -0
- relaydeck-0.1.0/relaydeck/audit.py +222 -0
- relaydeck-0.1.0/relaydeck/auth.py +155 -0
- relaydeck-0.1.0/relaydeck/auth_tokens.py +245 -0
- relaydeck-0.1.0/relaydeck/automation/__init__.py +42 -0
- relaydeck-0.1.0/relaydeck/automation/actions.py +481 -0
- relaydeck-0.1.0/relaydeck/automation/schedule.py +63 -0
- relaydeck-0.1.0/relaydeck/automation_runs.py +296 -0
- relaydeck-0.1.0/relaydeck/bundles.py +85 -0
- relaydeck-0.1.0/relaydeck/channels.py +337 -0
- relaydeck-0.1.0/relaydeck/config.py +449 -0
- relaydeck-0.1.0/relaydeck/daemon.py +258 -0
- relaydeck-0.1.0/relaydeck/dashboard_commands.py +170 -0
- relaydeck-0.1.0/relaydeck/db.py +1790 -0
- relaydeck-0.1.0/relaydeck/harness/__init__.py +27 -0
- relaydeck-0.1.0/relaydeck/harness/base.py +1246 -0
- relaydeck-0.1.0/relaydeck/harness_model.py +297 -0
- relaydeck-0.1.0/relaydeck/harness_options.py +686 -0
- relaydeck-0.1.0/relaydeck/integrations/__init__.py +239 -0
- relaydeck-0.1.0/relaydeck/integrations/classifier.py +79 -0
- relaydeck-0.1.0/relaydeck/integrations/claude.py +324 -0
- relaydeck-0.1.0/relaydeck/layouts.py +172 -0
- relaydeck-0.1.0/relaydeck/local_providers.py +143 -0
- relaydeck-0.1.0/relaydeck/maintenance.py +109 -0
- relaydeck-0.1.0/relaydeck/messages.py +616 -0
- relaydeck-0.1.0/relaydeck/metrics.py +382 -0
- relaydeck-0.1.0/relaydeck/model_invocations.py +296 -0
- relaydeck-0.1.0/relaydeck/model_roles.py +282 -0
- relaydeck-0.1.0/relaydeck/models/__init__.py +0 -0
- relaydeck-0.1.0/relaydeck/models_dev.py +372 -0
- relaydeck-0.1.0/relaydeck/orchestrator.py +1354 -0
- relaydeck-0.1.0/relaydeck/plugin.py +2088 -0
- relaydeck-0.1.0/relaydeck/plugin_disabled.py +88 -0
- relaydeck-0.1.0/relaydeck/plugin_install.py +478 -0
- relaydeck-0.1.0/relaydeck/plugin_lock.py +195 -0
- relaydeck-0.1.0/relaydeck/plugin_manifest.py +340 -0
- relaydeck-0.1.0/relaydeck/plugin_registry.py +126 -0
- relaydeck-0.1.0/relaydeck/plugin_settings.py +216 -0
- relaydeck-0.1.0/relaydeck/preferences.py +194 -0
- relaydeck-0.1.0/relaydeck/prompt_composition.py +185 -0
- relaydeck-0.1.0/relaydeck/prompts.py +711 -0
- relaydeck-0.1.0/relaydeck/provider.py +13 -0
- relaydeck-0.1.0/relaydeck/provider_config.py +102 -0
- relaydeck-0.1.0/relaydeck/providers_extra.py +284 -0
- relaydeck-0.1.0/relaydeck/providers_ollama.py +145 -0
- relaydeck-0.1.0/relaydeck/py.typed +1 -0
- relaydeck-0.1.0/relaydeck/screen.py +93 -0
- relaydeck-0.1.0/relaydeck/sdk.py +1689 -0
- relaydeck-0.1.0/relaydeck/semantic_engine.py +263 -0
- relaydeck-0.1.0/relaydeck/skills.py +639 -0
- relaydeck-0.1.0/relaydeck/skills_cache.py +247 -0
- relaydeck-0.1.0/relaydeck/state.py +299 -0
- relaydeck-0.1.0/relaydeck/tasks.py +322 -0
- relaydeck-0.1.0/relaydeck/testing.py +391 -0
- relaydeck-0.1.0/relaydeck/themes.py +451 -0
- relaydeck-0.1.0/relaydeck/tls.py +144 -0
- relaydeck-0.1.0/relaydeck/transports/__init__.py +0 -0
- relaydeck-0.1.0/relaydeck/transports/api.py +3668 -0
- relaydeck-0.1.0/relaydeck/transports/attach.py +429 -0
- relaydeck-0.1.0/relaydeck/transports/cli.py +7000 -0
- relaydeck-0.1.0/relaydeck/transports/view.py +1246 -0
- relaydeck-0.1.0/relaydeck/transports/viewers/__init__.py +212 -0
- relaydeck-0.1.0/relaydeck/transports/viewers/ghostty.py +362 -0
- relaydeck-0.1.0/relaydeck/transports/viewers/print_viewer.py +43 -0
- relaydeck-0.1.0/relaydeck/transports/viewers/tmux.py +175 -0
- relaydeck-0.1.0/relaydeck/utils/__init__.py +1 -0
- relaydeck-0.1.0/relaydeck/vault.py +75 -0
- relaydeck-0.1.0/relaydeck/version_check.py +134 -0
- relaydeck-0.1.0/relaydeck/web/__init__.py +0 -0
- relaydeck-0.1.0/relaydeck/web/static/app.js +1132 -0
- relaydeck-0.1.0/relaydeck/web/static/data.js +373 -0
- relaydeck-0.1.0/relaydeck/web/static/favicon.svg +10 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/LICENSE +13 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/fonts.css +253 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-300-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-300-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-400-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-400-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-500-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-500-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-600-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-mono-600-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-300-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-300-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-400-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-400-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-500-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-500-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-600-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-600-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-700-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/ibm-plex-sans-700-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-400-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-400-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-500-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-500-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-600-latin-ext.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/fonts/jetbrains-mono-600-latin.woff2 +0 -0
- relaydeck-0.1.0/relaydeck/web/static/harness_brand.js +124 -0
- relaydeck-0.1.0/relaydeck/web/static/home.js +1564 -0
- relaydeck-0.1.0/relaydeck/web/static/icon_data.js +69 -0
- relaydeck-0.1.0/relaydeck/web/static/index.html +35 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/agents.js +582 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/appearance.js +446 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/messages.js +378 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/models.js +1250 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/plugins.js +414 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/workers.js +752 -0
- relaydeck-0.1.0/relaydeck/web/static/lenses/workspaces.js +403 -0
- relaydeck-0.1.0/relaydeck/web/static/model_select.js +213 -0
- relaydeck-0.1.0/relaydeck/web/static/models.css +495 -0
- relaydeck-0.1.0/relaydeck/web/static/new_agent.js +1014 -0
- relaydeck-0.1.0/relaydeck/web/static/onboarding.js +517 -0
- relaydeck-0.1.0/relaydeck/web/static/overlays.js +1540 -0
- relaydeck-0.1.0/relaydeck/web/static/panels.css +1394 -0
- relaydeck-0.1.0/relaydeck/web/static/primitives.js +288 -0
- relaydeck-0.1.0/relaydeck/web/static/shell.js +292 -0
- relaydeck-0.1.0/relaydeck/web/static/styles.css +1406 -0
- relaydeck-0.1.0/relaydeck/web/static/theme.css +102 -0
- relaydeck-0.1.0/relaydeck/web/static/theme.js +91 -0
- relaydeck-0.1.0/relaydeck/web/static/tile_system.js +293 -0
- relaydeck-0.1.0/relaydeck/web/static/tiles/config.js +70 -0
- relaydeck-0.1.0/relaydeck/web/static/tiles/context.js +135 -0
- relaydeck-0.1.0/relaydeck/web/static/tiles/events.js +193 -0
- relaydeck-0.1.0/relaydeck/web/static/tiles/identity.js +468 -0
- relaydeck-0.1.0/relaydeck/web/static/tiles/raw.js +82 -0
- relaydeck-0.1.0/relaydeck/web/static/tiles/terminal.js +403 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/README.md +143 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/base.js +225 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/format.js +27 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/index.js +56 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/modal.js +84 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/reactive.js +84 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/settings-form.js +159 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/toggle.js +53 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/uikit.css +78 -0
- relaydeck-0.1.0/relaydeck/web/static/uikit/widgets.js +162 -0
- relaydeck-0.1.0/relaydeck/web/static/update_banner.js +163 -0
- relaydeck-0.1.0/relaydeck/web/static/vendor/lit-all.min.js +116 -0
- relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/LICENSE +29 -0
- relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/addon-fit.min.js +8 -0
- relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/addon-webgl.min.js +8 -0
- relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/xterm.min.css +8 -0
- relaydeck-0.1.0/relaydeck/web/static/vendor/xterm/xterm.min.js +8 -0
- relaydeck-0.1.0/relaydeck/web/static/worker_form.js +414 -0
- relaydeck-0.1.0/relaydeck/web/static/workers.css +717 -0
- relaydeck-0.1.0/relaydeck/web_runtime.py +47 -0
- relaydeck-0.1.0/relaydeck/workers.py +445 -0
- relaydeck-0.1.0/relaydeck/workspace_health.py +113 -0
- relaydeck-0.1.0/relaydeck/workspace_plugins.py +111 -0
- relaydeck-0.1.0/relaydeck/worktrees.py +685 -0
- relaydeck-0.1.0/scripts/bump_version.py +96 -0
- relaydeck-0.1.0/scripts/gen_web_icons.py +143 -0
- relaydeck-0.1.0/scripts/install-behavior.sh +58 -0
- relaydeck-0.1.0/scripts/install-smoke.sh +57 -0
- relaydeck-0.1.0/scripts/install.sh +176 -0
- relaydeck-0.1.0/scripts/test-install.sh +16 -0
- relaydeck-0.1.0/scripts/vendor_lit.sh +43 -0
- relaydeck-0.1.0/tests/README.md +76 -0
- relaydeck-0.1.0/tests/__init__.py +1 -0
- relaydeck-0.1.0/tests/conftest.py +121 -0
- relaydeck-0.1.0/tests/docker/Dockerfile.base +62 -0
- relaydeck-0.1.0/tests/docker/Dockerfile.pi +27 -0
- relaydeck-0.1.0/tests/docker/__init__.py +0 -0
- relaydeck-0.1.0/tests/docker/compose.yml +42 -0
- relaydeck-0.1.0/tests/docker/conftest.py +102 -0
- relaydeck-0.1.0/tests/docker/test_zero_bucket.py +219 -0
- relaydeck-0.1.0/tests/docker/test_zero_install_scripts.py +54 -0
- relaydeck-0.1.0/tests/e2e/__init__.py +0 -0
- relaydeck-0.1.0/tests/e2e/_webutil.py +384 -0
- relaydeck-0.1.0/tests/e2e/conftest.py +276 -0
- relaydeck-0.1.0/tests/e2e/test_cross_harness_messaging_e2e.py +151 -0
- relaydeck-0.1.0/tests/e2e/test_harness_integration_e2e.py +379 -0
- relaydeck-0.1.0/tests/e2e/test_pi_smoke.py +244 -0
- relaydeck-0.1.0/tests/e2e/test_relaydeck_native_smoke.py +67 -0
- relaydeck-0.1.0/tests/e2e/test_terminal_image_drop_e2e.py +179 -0
- relaydeck-0.1.0/tests/e2e/test_web_harness_e2e.py +178 -0
- relaydeck-0.1.0/tests/e2e/test_web_lens_scroll_e2e.py +116 -0
- relaydeck-0.1.0/tests/e2e/test_web_lit_regressions_e2e.py +175 -0
- relaydeck-0.1.0/tests/e2e/test_web_regression_e2e.py +369 -0
- relaydeck-0.1.0/tests/e2e/test_web_relaydeck_native_e2e.py +224 -0
- relaydeck-0.1.0/tests/e2e/test_web_settings_onboarding_e2e.py +340 -0
- relaydeck-0.1.0/tests/e2e/test_web_telegram_e2e.py +564 -0
- relaydeck-0.1.0/tests/e2e/test_web_workers_e2e.py +351 -0
- relaydeck-0.1.0/tests/install/Dockerfile +36 -0
- relaydeck-0.1.0/tests/test_access_log_filter.py +85 -0
- relaydeck-0.1.0/tests/test_agent_edit_editor.py +161 -0
- relaydeck-0.1.0/tests/test_agent_events_cli.py +113 -0
- relaydeck-0.1.0/tests/test_agent_id_validation.py +127 -0
- relaydeck-0.1.0/tests/test_agent_meta.py +418 -0
- relaydeck-0.1.0/tests/test_agent_preview_prompt.py +109 -0
- relaydeck-0.1.0/tests/test_agent_screen.py +158 -0
- relaydeck-0.1.0/tests/test_agent_screen_stopped.py +86 -0
- relaydeck-0.1.0/tests/test_agent_stats_accuracy.py +189 -0
- relaydeck-0.1.0/tests/test_agent_wait.py +155 -0
- relaydeck-0.1.0/tests/test_antigravity_harness.py +210 -0
- relaydeck-0.1.0/tests/test_atomicio.py +60 -0
- relaydeck-0.1.0/tests/test_attach.py +96 -0
- relaydeck-0.1.0/tests/test_audit.py +289 -0
- relaydeck-0.1.0/tests/test_auth.py +291 -0
- relaydeck-0.1.0/tests/test_auth_tokens.py +328 -0
- relaydeck-0.1.0/tests/test_automation_runs.py +575 -0
- relaydeck-0.1.0/tests/test_backpressure.py +230 -0
- relaydeck-0.1.0/tests/test_bump_version.py +57 -0
- relaydeck-0.1.0/tests/test_bundles.py +55 -0
- relaydeck-0.1.0/tests/test_bus_durability.py +296 -0
- relaydeck-0.1.0/tests/test_claude_code_harness.py +334 -0
- relaydeck-0.1.0/tests/test_claude_usage_tailer.py +147 -0
- relaydeck-0.1.0/tests/test_cli_cwd_scoping.py +309 -0
- relaydeck-0.1.0/tests/test_codex_harness.py +401 -0
- relaydeck-0.1.0/tests/test_config.py +264 -0
- relaydeck-0.1.0/tests/test_cursor_harness.py +115 -0
- relaydeck-0.1.0/tests/test_daemon_bind_host_pref.py +80 -0
- relaydeck-0.1.0/tests/test_daemon_lifecycle.py +178 -0
- relaydeck-0.1.0/tests/test_daemon_log.py +49 -0
- relaydeck-0.1.0/tests/test_dashboard_commands.py +208 -0
- relaydeck-0.1.0/tests/test_dashboard_redesign.py +170 -0
- relaydeck-0.1.0/tests/test_db.py +429 -0
- relaydeck-0.1.0/tests/test_db_maintenance.py +307 -0
- relaydeck-0.1.0/tests/test_db_migration.py +83 -0
- relaydeck-0.1.0/tests/test_db_pool.py +247 -0
- relaydeck-0.1.0/tests/test_external_agents_detector.py +113 -0
- relaydeck-0.1.0/tests/test_external_agents_plugin.py +206 -0
- relaydeck-0.1.0/tests/test_external_agents_probes.py +99 -0
- relaydeck-0.1.0/tests/test_external_agents_store.py +71 -0
- relaydeck-0.1.0/tests/test_external_spawn.py +181 -0
- relaydeck-0.1.0/tests/test_file_watcher.py +378 -0
- relaydeck-0.1.0/tests/test_github_plugin.py +986 -0
- relaydeck-0.1.0/tests/test_github_spawn.py +285 -0
- relaydeck-0.1.0/tests/test_harness_autonomy.py +243 -0
- relaydeck-0.1.0/tests/test_harness_injection_e2e.py +116 -0
- relaydeck-0.1.0/tests/test_harness_model.py +172 -0
- relaydeck-0.1.0/tests/test_harness_options.py +268 -0
- relaydeck-0.1.0/tests/test_harness_plugin_registration.py +77 -0
- relaydeck-0.1.0/tests/test_harness_pty.py +90 -0
- relaydeck-0.1.0/tests/test_harness_pty_resize.py +128 -0
- relaydeck-0.1.0/tests/test_harness_reap.py +123 -0
- relaydeck-0.1.0/tests/test_harness_sdk.py +191 -0
- relaydeck-0.1.0/tests/test_harness_skill_injection_matrix.py +132 -0
- relaydeck-0.1.0/tests/test_hitl.py +235 -0
- relaydeck-0.1.0/tests/test_home_widgets_manifest.py +64 -0
- relaydeck-0.1.0/tests/test_inbox_stream.py +239 -0
- relaydeck-0.1.0/tests/test_install_script.py +104 -0
- relaydeck-0.1.0/tests/test_integrations.py +746 -0
- relaydeck-0.1.0/tests/test_interactive_prompts.py +527 -0
- relaydeck-0.1.0/tests/test_layouts.py +171 -0
- relaydeck-0.1.0/tests/test_local_providers.py +143 -0
- relaydeck-0.1.0/tests/test_log_privacy.py +103 -0
- relaydeck-0.1.0/tests/test_loop_agent.py +463 -0
- relaydeck-0.1.0/tests/test_maintenance.py +132 -0
- relaydeck-0.1.0/tests/test_messaging.py +1465 -0
- relaydeck-0.1.0/tests/test_messaging_durability.py +318 -0
- relaydeck-0.1.0/tests/test_messaging_reliability.py +607 -0
- relaydeck-0.1.0/tests/test_metering_pricing.py +116 -0
- relaydeck-0.1.0/tests/test_model_invocations.py +225 -0
- relaydeck-0.1.0/tests/test_model_resolve.py +141 -0
- relaydeck-0.1.0/tests/test_model_roles.py +297 -0
- relaydeck-0.1.0/tests/test_models_dev.py +307 -0
- relaydeck-0.1.0/tests/test_observability.py +348 -0
- relaydeck-0.1.0/tests/test_opencode_harness.py +302 -0
- relaydeck-0.1.0/tests/test_orchestrator.py +406 -0
- relaydeck-0.1.0/tests/test_pi_engine.py +548 -0
- relaydeck-0.1.0/tests/test_pi_harness.py +197 -0
- relaydeck-0.1.0/tests/test_plugin.py +177 -0
- relaydeck-0.1.0/tests/test_plugin_boundary.py +66 -0
- relaydeck-0.1.0/tests/test_plugin_disable.py +193 -0
- relaydeck-0.1.0/tests/test_plugin_ecosystem_gaps.py +121 -0
- relaydeck-0.1.0/tests/test_plugin_platform.py +2324 -0
- relaydeck-0.1.0/tests/test_plugin_registry.py +96 -0
- relaydeck-0.1.0/tests/test_plugin_scaffold_cli.py +102 -0
- relaydeck-0.1.0/tests/test_plugin_settings_g1.py +131 -0
- relaydeck-0.1.0/tests/test_plugin_trust_level.py +165 -0
- relaydeck-0.1.0/tests/test_preferences.py +90 -0
- relaydeck-0.1.0/tests/test_prompt_composition.py +198 -0
- relaydeck-0.1.0/tests/test_provider_config.py +256 -0
- relaydeck-0.1.0/tests/test_providers.py +285 -0
- relaydeck-0.1.0/tests/test_relaydeck_native.py +755 -0
- relaydeck-0.1.0/tests/test_relaydeck_native_repl.py +235 -0
- relaydeck-0.1.0/tests/test_reply_nudge.py +335 -0
- relaydeck-0.1.0/tests/test_runtime_stats.py +63 -0
- relaydeck-0.1.0/tests/test_semantic_engine.py +232 -0
- relaydeck-0.1.0/tests/test_semantic_status.py +275 -0
- relaydeck-0.1.0/tests/test_skills.py +460 -0
- relaydeck-0.1.0/tests/test_skills_plugin.py +508 -0
- relaydeck-0.1.0/tests/test_static_cache_headers.py +41 -0
- relaydeck-0.1.0/tests/test_status_cli.py +297 -0
- relaydeck-0.1.0/tests/test_system_prompt.py +373 -0
- relaydeck-0.1.0/tests/test_tasks.py +229 -0
- relaydeck-0.1.0/tests/test_telegram_commands.py +203 -0
- relaydeck-0.1.0/tests/test_telegram_conversation_purge.py +150 -0
- relaydeck-0.1.0/tests/test_telegram_plugin.py +1737 -0
- relaydeck-0.1.0/tests/test_terminal.py +421 -0
- relaydeck-0.1.0/tests/test_terminal_image_upload.py +431 -0
- relaydeck-0.1.0/tests/test_testing_helpers.py +144 -0
- relaydeck-0.1.0/tests/test_themes.py +433 -0
- relaydeck-0.1.0/tests/test_tls.py +234 -0
- relaydeck-0.1.0/tests/test_usage_heatmap.py +120 -0
- relaydeck-0.1.0/tests/test_usage_limits.py +584 -0
- relaydeck-0.1.0/tests/test_vault_encryption.py +274 -0
- relaydeck-0.1.0/tests/test_version_check.py +95 -0
- relaydeck-0.1.0/tests/test_view.py +274 -0
- relaydeck-0.1.0/tests/test_viewers.py +323 -0
- relaydeck-0.1.0/tests/test_web_runtime.py +50 -0
- relaydeck-0.1.0/tests/test_worker_agent_cleanup.py +172 -0
- relaydeck-0.1.0/tests/test_worker_supervision.py +270 -0
- relaydeck-0.1.0/tests/test_workers_cli.py +129 -0
- relaydeck-0.1.0/tests/test_workspace_api.py +416 -0
- relaydeck-0.1.0/tests/test_workspace_cwd_resolution.py +209 -0
- relaydeck-0.1.0/tests/test_workspace_health.py +98 -0
- relaydeck-0.1.0/tests/test_workspace_view.py +127 -0
- relaydeck-0.1.0/tests/test_worktrees.py +713 -0
- 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
|