Skip to content

feat(runtime): remote daemon log view + restart - #11

Merged
wujunyi792 merged 2 commits into
mainfrom
feat/remote-daemon-logs-restart
Jul 22, 2026
Merged

wujunyi792 merged 2 commits into
mainfrom
feat/remote-daemon-logs-restart

Conversation

@wujunyi792

Copy link
Copy Markdown
Member

Why

Server-side, only remote update existed; viewing daemon logs and restarting were local-CLI only (multica daemon logs / daemon restart). This adds both as remote controls, over the same heartbeat-pending channel remote-update already uses.

Mechanism (mirrors remote update)

POST creates a pending request → the daemon claims it on its next heartbeat → executes → reports a terminal result → the UI polls by id.

  • protocol: PendingRestart{force} + PendingLogFetch{lines} on the heartbeat ack.
  • server: one generic RuntimeCommandStore (kind = restart | logs; in-memory default + Redis for multi-node) backs both. Handlers RestartRuntime / FetchRuntimeLogs / GetRuntimeCommand / ReportRuntimeCommandResult; the heartbeat pops the command and attaches the matching pending action; owner/admin-gated.
  • daemon: handleRestart reuses the auto-update self-restart (triggerRestart) — graceful drains in-flight tasks first (bounded 10 min), force restarts immediately; Desktop-managed daemons refuse. handleLogFetch tails its own daemon.log (snapshot, 512 KB cap) — path plumbed via cfg.LogPath. New client report method.
  • frontend: RuntimeCommand type + api.restartRuntime/fetchRuntimeLogs/getRuntimeCommand; DaemonControlSection (View logs + Restart with two-step confirm and poll-to-terminal) under the machine CLI section. i18n en/zh/ja/ko.

Decisions: logs = snapshot pull (last N lines, no live WS stream); restart = graceful drain default.

Tests

tailLogFileContent (line/byte caps, missing file), the in-memory store lifecycle (single-in-flight, pop→running, complete/fail), and the heartbeat-attach mapping (restart→PendingRestart, logs→PendingLogFetch). go build/vet, core+views typecheck, full @multica/views vitest (2914).

Not covered

A live daemon round-trip wasn't run — no daemon is connected in this environment and standing one up needs the full agent-CLI + login setup. The server and daemon halves are unit-tested and the wiring faithfully mirrors the proven remote-update flow; a live check is a good follow-up once a daemon is attached.

🤖 Generated with Claude Code

wujunyi792 and others added 2 commits July 22, 2026 15:24
Previously only remote CLI *update* could be triggered server-side; viewing
daemon logs and restarting were local-CLI only (`multica daemon logs/restart`).
Add both as remote controls over the existing heartbeat-pending channel, the
same lifecycle as remote update (POST creates a pending request, the daemon
claims it on heartbeat, reports a terminal result, the UI polls by id).

- protocol: PendingRestart (force) + PendingLogFetch (lines) on the heartbeat ack.
- server: one generic RuntimeCommandStore (kind=restart|logs; InMemory default +
  Redis for multi-node) backs both; handlers RestartRuntime / FetchRuntimeLogs /
  GetRuntimeCommand / ReportRuntimeCommandResult; heartbeat attaches the popped
  command; owner/admin-gated.
- daemon: handleRestart reuses the auto-update self-restart (triggerRestart) —
  graceful drains in-flight tasks first (bounded), force restarts immediately;
  Desktop-managed daemons refuse. handleLogFetch tails its own daemon.log
  (snapshot, byte-capped) — path plumbed via cfg.LogPath. Reports via a new
  client method.
- frontend: RuntimeCommand type + api.restartRuntime/fetchRuntimeLogs/
  getRuntimeCommand; DaemonControlSection (View logs + Restart, with confirm and
  a poll-to-terminal) mounted under the machine CLI section. i18n en/zh/ja/ko.

Logs are snapshot pull (last N lines), not a live stream. Restart defaults to
graceful drain. Tests: tailLogFileContent (line/byte caps, missing file) and the
in-memory store lifecycle (single-in-flight, pop→running, complete/fail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYStwEXJFCJLokYqKVUBUg
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYStwEXJFCJLokYqKVUBUg
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@wujunyi792, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cf5e86c7-3b41-4ffb-9c2a-f8b6c9f7e31e

📥 Commits

Reviewing files that changed from the base of the PR and between 1c65a2a and 4643d42.

📒 Files selected for processing (22)
  • packages/core/api/client.ts
  • packages/core/types/agent.ts
  • packages/core/types/index.ts
  • packages/views/locales/en/runtimes.json
  • packages/views/locales/ja/runtimes.json
  • packages/views/locales/ko/runtimes.json
  • packages/views/locales/zh-Hans/runtimes.json
  • packages/views/runtimes/components/daemon-control-section.tsx
  • packages/views/runtimes/components/machine-cli-section.tsx
  • server/cmd/multica/cmd_daemon.go
  • server/cmd/server/router.go
  • server/internal/daemon/client.go
  • server/internal/daemon/config.go
  • server/internal/daemon/daemon.go
  • server/internal/daemon/remote_control.go
  • server/internal/daemon/remote_control_test.go
  • server/internal/handler/daemon.go
  • server/internal/handler/handler.go
  • server/internal/handler/runtime_command.go
  • server/internal/handler/runtime_command_redis_store.go
  • server/internal/handler/runtime_command_test.go
  • server/pkg/protocol/messages.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/remote-daemon-logs-restart

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@wujunyi792
wujunyi792 merged commit a7e8e46 into main Jul 22, 2026
7 checks passed
@wujunyi792
wujunyi792 deleted the feat/remote-daemon-logs-restart branch July 22, 2026 07:26
wujunyi792 added a commit that referenced this pull request Aug 24, 2026
* feat(runtime): remote daemon log view + restart

Previously only remote CLI *update* could be triggered server-side; viewing
daemon logs and restarting were local-CLI only (`multica daemon logs/restart`).
Add both as remote controls over the existing heartbeat-pending channel, the
same lifecycle as remote update (POST creates a pending request, the daemon
claims it on heartbeat, reports a terminal result, the UI polls by id).

- protocol: PendingRestart (force) + PendingLogFetch (lines) on the heartbeat ack.
- server: one generic RuntimeCommandStore (kind=restart|logs; InMemory default +
  Redis for multi-node) backs both; handlers RestartRuntime / FetchRuntimeLogs /
  GetRuntimeCommand / ReportRuntimeCommandResult; heartbeat attaches the popped
  command; owner/admin-gated.
- daemon: handleRestart reuses the auto-update self-restart (triggerRestart) —
  graceful drains in-flight tasks first (bounded), force restarts immediately;
  Desktop-managed daemons refuse. handleLogFetch tails its own daemon.log
  (snapshot, byte-capped) — path plumbed via cfg.LogPath. Reports via a new
  client method.
- frontend: RuntimeCommand type + api.restartRuntime/fetchRuntimeLogs/
  getRuntimeCommand; DaemonControlSection (View logs + Restart, with confirm and
  a poll-to-terminal) mounted under the machine CLI section. i18n en/zh/ja/ko.

Logs are snapshot pull (last N lines), not a live stream. Restart defaults to
graceful drain. Tests: tailLogFileContent (line/byte caps, missing file) and the
in-memory store lifecycle (single-in-flight, pop→running, complete/fail).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYStwEXJFCJLokYqKVUBUg

* test(runtime): heartbeat-attach mapping for remote commands

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYStwEXJFCJLokYqKVUBUg

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant