Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e006928
fix: retain Discord event lease after timeout (#769)
roomote-roomote[bot] Jul 25, 2026
697272a
[Feat] Add Z.AI and Z.AI Coding Plan inference providers (#765)
pridemusvaire Jul 25, 2026
8120bcc
[Fix] Review public fork pull requests without fork access (#774)
roomote-roomote[bot] Jul 25, 2026
a9f97b4
[Fix] Docker environments fail to start on nft-only hosts (#775)
roomote-roomote[bot] Jul 25, 2026
94ed570
[Feat] Add internal TLS mode for self-hosted installs (#776)
roomote-roomote[bot] Jul 25, 2026
2ce1446
[Fix] Task analytics count environment snapshot maintenance (#777)
roomote-roomote[bot] Jul 25, 2026
8b64393
Dispatch notify-ops on main builds only (#779)
mrubens Jul 25, 2026
2d58e87
[Improve] Show Dependabot triage completion status (#780)
roomote-roomote[bot] Jul 25, 2026
bb9823e
[Improve] Show Dependabot triage completion status (#781)
roomote-roomote[bot] Jul 25, 2026
ef72661
chore(deps): update Better Auth security fix (#782)
roomote-roomote[bot] Jul 25, 2026
69e3cb9
[Improve] Explain dependency update impact (#783)
roomote-roomote[bot] Jul 25, 2026
2f4ee9d
improve(automation): cover multiple Dependabot environments (#784)
roomote-roomote[bot] Jul 25, 2026
9a05b29
[Improve] Show the latest subagent message (#786)
roomote-roomote[bot] Jul 26, 2026
1f67150
[Chore] Resolve Dependabot alert bundle (#788)
roomote-roomote[bot] Jul 26, 2026
26761ba
[Fix] Automation scans post Slack messages before results (#787)
roomote-roomote[bot] Jul 26, 2026
8bd5579
[Fix] Restrict non-task OpenCode sessions to text-only output (#790)
mrubens Jul 26, 2026
bb78c0f
[Chore] Prepare Roomote 0.21.0 release (#789)
roomote-roomote[bot] Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.production.example
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ OPENROUTER_API_KEY=
# MOONSHOT_API_KEY=
# KIMI_API_KEY=
# MINIMAX_API_KEY=
# ZAI_API_KEY=
# ZAI_REGION=global
# ZAI_CODING_PLAN_API_KEY=
# ZAI_CODING_PLAN_REGION=global
# OPENCODE_API_KEY=

# Compute provider. Use docker for a single-host deployment, or
Expand Down
18 changes: 3 additions & 15 deletions .github/workflows/publish-ghcr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ jobs:
name: Notify ops repository
runs-on: ubuntu-latest
needs: publish
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main') && vars.ROOMOTE_OPS_REPO != '' }}
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && vars.ROOMOTE_OPS_REPO != '' }}
permissions:
contents: read
steps:
Expand All @@ -480,20 +480,8 @@ jobs:
run: |
set -euo pipefail
: "${GH_TOKEN:?ROOMOTE_OPS_DISPATCH_TOKEN is required}"
case "$GITHUB_REF" in
refs/heads/develop)
event_type=roomote-develop-build
image_tag="develop-${GITHUB_SHA:0:8}"
;;
refs/heads/main)
event_type=roomote-main-build
image_tag="main-${GITHUB_SHA:0:8}"
;;
*)
echo "Unexpected ref for notify-ops: $GITHUB_REF" >&2
exit 1
;;
esac
event_type=roomote-main-build
image_tag="main-${GITHUB_SHA:0:8}"
gh api "repos/${OPS_REPO}/dispatches" \
-f "event_type=${event_type}" \
-f "client_payload[image_tag]=${image_tag}" \
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

This file tracks product releases for Roomote (single monorepo version). Automated release entries are prepended by `pnpm run version`.

## 0.21.0 (2026-07-26)

This release expands self-hosted deployment options and inference-provider choice, while making agent activity and automation more reliable and secure.

### Highlights

- Deploy self-hosted Roomote behind private networks and reverse tunnels with supported internal TLS.
- Add Z.AI and Z.AI Coding Plan as inference providers, with International and China region selection. Thanks to @pridemusvaire for this contribution.
- Keep task titles, routing, and summaries safely text-only when they process externally supplied input.
- Inspect the latest response from a subagent while it runs and after it completes.

### Minor changes

- Support internal TLS for self-hosted deployments behind reverse tunnels and private networks, without requiring public DNS or a custom Caddyfile.
- Add Z.AI and Z.AI Coding Plan as inference providers with International or China region on connect.

### Patch changes

- Restrict non-task OpenCode sessions to text-only output so task titles, routing, and summaries cannot act on instruction-like input.
- Keep Discord event handling and public-fork pull-request reviews reliable, while allowing self-hosted Docker environments to start on nftables-only hosts.
- Show the latest response from running and completed subagents, and give Dependabot automation clearer impact analysis and completion reporting.

## 0.20.1 (2026-07-25)

This release makes chat-driven automation more reliable, keeping Discord tasks moving and report-thread replies connected to their work.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ cleans up after itself.
2. **API keys (BYOK).** Paste a key from OpenRouter, Anthropic, OpenAI, xAI,
Google Gemini, Amazon Bedrock, Vercel AI Gateway,
Baseten, Together AI, Moonshot AI (Kimi), Kimi for Coding, MiniMax,
OpenCode Zen / Go, or GitHub Copilot.
Z.AI (including Coding Plan), OpenCode Zen / Go, or GitHub Copilot.

**Sandbox compute:** Modal, E2B, Daytona, Blaxel, and Local Docker.

Expand Down Expand Up @@ -231,8 +231,8 @@ it runs.
Two options. Connect your ChatGPT Plus or Pro subscription directly (no API key
needed), or paste an API key from OpenRouter, Anthropic, OpenAI, xAI, Google
Gemini, Amazon Bedrock, Vercel AI Gateway, Baseten,
Together AI, Moonshot AI (Kimi), Kimi for Coding, MiniMax, OpenCode Zen / Go,
or GitHub Copilot.
Together AI, Moonshot AI (Kimi), Kimi for Coding, MiniMax, Z.AI (including
Coding Plan), OpenCode Zen / Go, or GitHub Copilot.

**What sandboxes does it support?**
Modal, E2B, Daytona, Blaxel, and Local Docker.
Expand Down
29 changes: 26 additions & 3 deletions SELF_HOSTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ Point `<domain>`, `preview.<domain>`, and `*.preview.<domain>` A records at
the server first; the installer waits briefly for DNS and Caddy retries
certificates until the records are in place.

### Private networks and tunnels

When a reverse tunnel or private network terminates public TLS before traffic
reaches Roomote, use Caddy's internal certificates instead of requesting
Let's Encrypt certificates:

```sh
curl -fsSL https://get.roomote.dev | bash -s -- \
--domain roomote.internal \
--tls-mode internal
```

`--tls-mode internal` skips public-DNS verification and configures Caddy to
issue local certificates; it requires `--domain`. Direct private-network
clients must trust Caddy's local CA, while clients behind a tunnel use the
tunnel's public certificate. Use `--skip-dns-check` with the default `acme`
mode only when you know public DNS is not ready yet. The selected mode is
retained in `/opt/roomote/.env`, so installer reruns and `roomote upgrade`
preserve it.

Useful flags and env vars: `--version <tag>` pins a release, and
`--preview-domain <host>` overrides the preview root. Both published images
are public, so pulls need no credentials. Re-running the installer is safe:
Expand Down Expand Up @@ -294,6 +314,9 @@ common provider keys into worker containers:
- `MOONSHOT_API_KEY`
- `KIMI_API_KEY` (Kimi for Coding, `kimi-for-coding/...` models)
- `MINIMAX_API_KEY`
- `ZAI_API_KEY` (with `ZAI_REGION`: `global` or `china`, defaults to `global`)
- `ZAI_CODING_PLAN_API_KEY` (Z.AI Coding Plan, `zai-coding-plan/...` models,
with `ZAI_CODING_PLAN_REGION`)
- `OPENCODE_API_KEY`

If your provider uses another env var name, list it in
Expand Down Expand Up @@ -582,9 +605,9 @@ using Docker sandboxes. That overlay:
and, under the default `internet` egress policy, blackholes private and
cloud metadata ranges plus drops packets destined to the Docker bridge
gateway (host hairpin) while still allowing public egress via that gateway
as next-hop. The gateway drop is installed with `iptables`, so the worker
image must ship an iptables binary the host kernel supports (the stock
image does); sandbox provisioning fails closed when it is unavailable;
as next-hop. The gateway drop automatically selects an nftables or legacy
`iptables` backend supported by the host kernel; sandbox provisioning fails
closed when neither backend is available;
- points `DOCKER_WORKER_RELEASE_PATH` at the controller image's packaged worker
release archive.

Expand Down
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"dependencies": {
"@aws-sdk/client-s3": "3.1000.0",
"@aws-sdk/s3-request-presigner": "3.1000.0",
"@hono/node-server": "1.19.13",
"@hono/node-server": "2.0.5",
"@hono/trpc-server": "^0.4.2",
"@modelcontextprotocol/sdk": "^1.29.0",
"@octokit/openapi-webhooks-types": "^12.1.0",
Expand Down
8 changes: 8 additions & 0 deletions apps/api/src/__tests__/sentry.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions apps/api/src/handlers/discord/__tests__/event-gate.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 34 additions & 3 deletions apps/api/src/handlers/discord/__tests__/index.test.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions apps/api/src/handlers/discord/event-gate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const DISCORD_API_EVENT_DEDUPE_PREFIX = 'discord:api:event:';
const DISCORD_API_EVENT_DEDUPE_TTL_SECONDS = 7 * 24 * 60 * 60;
const DISCORD_API_EVENT_PROCESSING_TTL_SECONDS = 5 * 60;

export const discordApiEventLeaseRenewal = {
intervalMs: 60 * 1000,
};

const CLAIM_EVENT_SCRIPT = `
local existing = redis.call('GET', KEYS[1])
if existing == 'done' then
Expand Down Expand Up @@ -40,6 +44,13 @@ end
return redis.call('DEL', KEYS[1])
`;

const RENEW_EVENT_SCRIPT = `
if redis.call('GET', KEYS[1]) ~= ARGV[1] then
return false
end
return redis.call('EXPIRE', KEYS[1], ARGV[2])
`;

function eventKey(eventType: string, eventId: string): string {
return `${DISCORD_API_EVENT_DEDUPE_PREFIX}${eventType}:${eventId}`;
}
Expand Down Expand Up @@ -96,3 +107,19 @@ export async function releaseDiscordApiEvent(input: {
);
return result === 1;
}

/** Keep an owned lease from expiring while its handler is still running. */
export async function renewDiscordApiEvent(input: {
eventType: string;
eventId: string;
token: string;
}): Promise<boolean> {
const result = await getRedis().eval(
RENEW_EVENT_SCRIPT,
1,
eventKey(input.eventType, input.eventId),
input.token,
DISCORD_API_EVENT_PROCESSING_TTL_SECONDS.toString(),
);
return result === 1;
}
Loading
Loading