Skip to content

feat(desktop): add managed remote Runtime Host onboarding - #3236

Merged
M4n5ter merged 19 commits into
mainfrom
feat/desktop-managed-remote-onboarding
Aug 21, 2026
Merged

feat(desktop): add managed remote Runtime Host onboarding#3236
M4n5ter merged 19 commits into
mainfrom
feat/desktop-managed-remote-onboarding

Conversation

@M4n5ter

@M4n5ter M4n5ter commented Aug 19, 2026

Copy link
Copy Markdown
Member

Summary

English
  • Add an Add computer flow that installs, pairs, verifies, and connects a Linux Runtime Host from one SSH destination
  • Keep credentials in the main process, preserve manual profiles for advanced endpoints, and continue directly to remote Project selection
  • Let unpackaged Desktop builds upload a content-addressed local CLI archive for realistic development testing
  • Require packaged Desktop releases to select an exact Maka CLI setup package that is already published

Fixes #3233

简体中文
  • 新增添加电脑流程,只需一个 SSH destination,即可完成 Linux Runtime Host 的安装、配对、验证与连接
  • Credential 始终留在 main process;高级 endpoint 仍可手工配置;连接成功后可直接选择远端 Project
  • 未打包 Desktop 可上传带内容版本的本地 CLI archive,用于真实开发验证
  • 打包 Desktop 时必须显式选择一个已经发布的精确 Maka CLI setup package

修复 #3233

Verification

English
  • npm run build:test
  • npm run typecheck
  • npm run lint
  • npm run format:check
  • 53 focused Desktop and Runtime Host tests passed
  • Computer Use against a real Linux systemd user service: uploaded a development archive, connected the Host, and loaded the remote Project picker
简体中文
  • npm run build:test
  • npm run typecheck
  • npm run lint
  • npm run format:check
  • 53 项 Desktop 与 Runtime Host 定向测试通过
  • 使用 Computer Use 对真实 Linux systemd user service 验证:上传开发 archive、连接 Host,并成功加载远端 Project picker

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex implemented the Desktop onboarding flow, SSH orchestration, development-package path, tests, and documentation under maintainer direction

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2fabf7eb-c533-445e-8630-1dbc6b5858b7

📥 Commits

Reviewing files that changed from the base of the PR and between 0673602 and 26ddf61.

📒 Files selected for processing (15)
  • apps/desktop/electron-builder.config.mjs
  • apps/desktop/src/main/runtime-host-boot.ts
  • apps/desktop/src/main/runtime-host-client.ts
  • apps/desktop/src/main/runtime-host-pairing-journal.ts
  • apps/desktop/src/preload/bridge-contract.d.ts
  • apps/desktop/src/preload/preload.ts
  • apps/desktop/src/renderer/settings/settings-surface.tsx
  • apps/desktop/stories/settings/settings-pages.stories.tsx
  • packages/cli/src/__tests__/runtime-host-cli-context.test.ts
  • packages/runtime-host/src/client/host-profile.ts
  • packages/runtime-host/src/client/index.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/server/connection-session.ts
  • packages/runtime-host/src/server/host-kernel.ts
  • scripts/release-cli-package.mjs
📝 Walkthrough

Problem solved

This PR adds a guided Desktop flow for adding a Linux Runtime Host through SSH. The flow:

  • Accepts an SSH destination, optional port, and optional display name.
  • Installs, pairs, verifies, and connects the Runtime Host.
  • Shows setup progress and supports cancellation, retry, reset, and actionable errors.
  • Keeps credentials in the main process and credential store.
  • Redacts credentials from renderer state and terminal output.
  • Saves the Profile only after verification.
  • Opens remote Project selection after success.
  • Preserves manual TLS and SSH Profile configuration.

Source of truth

The PR extends the existing Desktop, CLI, Runtime Host, Profile, credential, OpenSSH, systemd, and IPC contracts. It does not add a separate credential authority or Profile system.

The guided flow adds a new onboarding entry point over the existing managed setup path. Manual Profile configuration remains a separate supported path.

Solution size and complexity

The implementation is the smallest coherent solution for the requested transactional behavior.

The prepare/finalize credential flow prevents credential commitment before verification. Retry handling addresses connection loss and unknown commit outcomes. Profile rebinding and rollback protect existing Profiles. SSH cancellation escalation prevents setup processes and archive uploads from remaining active.

The implementation adds coordination across the main process, preload bridge, renderer, CLI, and Runtime Host protocol. This scope matches the requested onboarding, security, recovery, and development-package behavior.

The following code may be simplified later without weakening behavior if equivalent coverage remains:

  • Shared setup-frame parsing and process-lifecycle helpers.
  • Repeated onboarding snapshot and callback plumbing.
  • Repeated test fixtures for credential and Profile failure cases.

Rollback, retry, cancellation, redaction, and failure-path tests should remain. They cover security-sensitive and transactional behavior.

Validation and risks

The PR reports:

  • 943 passing Desktop tests.
  • Successful typecheck, lint, and format checks.
  • Verification against a real Linux systemd user service.

The tests cover credential and progress isolation, pairing finalization recovery, cancellation and forced termination, Profile replacement and rollback, credential preparation and revocation, development archive upload, service restart behavior, compatibility handling, and release-version handling.

These checks were not independently verified in the available evidence. Required-check status remains unverified.

Complexity delta

The PR adds:

  • Managed onboarding orchestration in the Desktop main process.
  • Revisioned onboarding snapshots and lifecycle states.
  • IPC methods for snapshot retrieval, start, cancel, reset, and subscription.
  • SSH setup, framed progress parsing, archive upload, timeouts, and termination escalation.
  • Prepare/finalize credential states with expiry and unknown-commit handling.
  • Profile rebinding and transactional rollback.
  • A compatibility epoch increment.
  • Packaged and development setup-package resolution.
  • Renderer callbacks, localized setup states, and post-onboarding Project selection.
  • Additional failure and recovery test maintenance.

The PR removes or consolidates:

  • Repeated credential mutation logic through shared issue, prepare, replace, and revoke flows.
  • Ambiguous development package versions through deterministic content-addressed versions.
  • Direct replacement cleanup paths where conditional rebinding is required.
  • Restart=on-failure, replaced by Restart=always.

Total maintenance complexity increases locally. The increase is justified by the required credential isolation, transactional pairing, retry safety, cancellation guarantees, and packaged/development setup support. The reported validation supports this conclusion, but required checks remain unverified.

Review-relevant risks

  • The PR changes user-visible Desktop onboarding, navigation, localized text, and remote Project selection. Material changes in these areas require independent human review under repository policy.
  • The PR changes public preload types, Desktop APIs, CLI setup options, Runtime Host protocol operations, and the compatibility epoch. Material public-contract changes require independent human review under repository policy.
  • The PR changes credential issuance, preparation, finalization, expiry, revocation, storage, and rollback. Material security changes require independent human review under repository policy.
  • The PR changes CLI versions, release manifests, packaged setup metadata, development archives, and systemd restart behavior. Material release and operational changes require independent human review under repository policy.
  • The PR adds contribution guidance and remote setup documentation. Material governance or operational-process changes require independent human review under repository policy.

The person performing the merge reviews the final diff. A maintainer makes the final determination.

Walkthrough

Desktop adds guided SSH onboarding for remote Runtime Hosts. The change adds deferred credential pairing, durable pairing recovery, framed SSH setup, onboarding IPC, Settings UI, project selection, CLI package handling, and validation coverage.

Changes

Remote Runtime Host onboarding

Layer / File(s) Summary
Credential pairing and profile recovery
packages/runtime-host/src/protocol/*, packages/runtime-host/src/server/*, packages/runtime-host/src/client/host-profile.ts, apps/desktop/src/main/runtime-host-profile-service.ts
Credentials support preparation, finalization, expiry, uncertain commit outcomes, and conditional profile rebinding. Desktop journals pairing intents and recovers or rolls back interrupted pairing.
CLI setup and package deployment
packages/cli/src/*, scripts/release-cli-package.mjs, packages/cli/package.json
CLI setup parses deferred pairing, prepares and revokes credentials, accepts compatible development versions, and configures service restart behavior.
Desktop SSH setup and onboarding orchestration
apps/desktop/src/main/runtime-host-*.ts, apps/desktop/electron-builder.config.mjs
Desktop resolves setup packages, uploads development archives, runs setup over SSH, parses progress frames, manages cancellation, validates endpoints, finalizes pairing, and persists verified profiles.
Onboarding bridge and Settings flow
apps/desktop/src/preload/*, apps/desktop/src/renderer/settings/*, apps/desktop/src/renderer/app-shell.tsx, apps/desktop/src/renderer/use-new-task-target.ts
IPC exposes onboarding snapshots. Settings provides Add computer, progress, retry, cancellation, completion, and project selection flows.
Validation and documentation
apps/desktop/src/main/__tests__/*, packages/cli/src/__tests__/*, packages/runtime-host/src/__tests__/*, CONTRIBUTING*, docs/*
Tests cover pairing recovery, cancellation, credential isolation, rollback, package replacement, service behavior, and local archive verification.

Estimated code review effort: 5 (Critical) | ~120 minutes

Merge Risk: 🟠 High · up to 06736

This PR adds managed Linux Runtime Host onboarding, pairing, and deployment, but the current implementation can expose pairing credentials in recovery files, resurrect revoked credentials after failed writes, ignore deployment cleanup failures, and leave onboarding stuck without an error message. These security, rollback, and usability risks should be fixed before merge.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Settings
  participant DesktopOnboarding
  participant SSH
  participant RuntimeHost
  User->>Settings: Enter SSH destination
  Settings->>DesktopOnboarding: Start onboarding
  DesktopOnboarding->>SSH: Run setup package
  SSH->>RuntimeHost: Upload and execute setup
  RuntimeHost-->>SSH: Return progress and credential
  SSH-->>DesktopOnboarding: Return setup result
  DesktopOnboarding->>RuntimeHost: Verify and finalize pairing
  DesktopOnboarding-->>Settings: Publish completed profile
  Settings->>User: Open project picker
Loading

Possibly related issues

  • maka-agent/maka-agent#3228 — Covers the tracked Desktop Add Computer SSH onboarding and pairing flow.

Possibly related PRs

Suggested reviewers: astro-han

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the primary change: managed remote Runtime Host onboarding for Desktop.
Description check ✅ Passed The description includes the required summary, issue reference, verification results, AI disclosure, checklist, behavior change, and supporting evidence.
Linked Issues check ✅ Passed The changes implement the linked issue’s Add Computer flow, SSH setup, credential protection, verification, recovery, retries, project selection, and manual profile compatibility.
Out of Scope Changes check ✅ Passed The changes support the onboarding objectives and include aligned tests, documentation, protocol updates, recovery logic, and development-package support without clear unrelated scope.
Ai Use Disclosure ✅ Passed The PR selects generative tooling and names OpenAI Codex with scope; all 10 introduced commits contain standalone Generated-by: Codex trailers consistent with that disclosure.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch feat/desktop-managed-remote-onboarding
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/desktop-managed-remote-onboarding

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

@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from 956157c to 0427296 Compare August 19, 2026 05:47
@M4n5ter

M4n5ter commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-code-review

qodo-code-review Bot commented Aug 19, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Project continuation rejects unhandled ✓ Resolved 🐞 Bug ☼ Reliability
Description
Fix-now: the new onRemoteHostAdded callback discards chooseProjectForProfile() without a
rejection handler, while that function propagates catalog-refresh failures. A transient
newTasks.getCatalog() failure therefore produces an unhandled promise rejection instead of a
controlled post-onboarding fallback.
Code

apps/desktop/src/renderer/app-shell.tsx[3594]

+          void newTask.chooseProjectForProfile(profileId);
Relevance

●●● Strong

Recent renderer precedent accepts preventing unhandled asynchronous failures.

PR-#3147

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
chooseProjectForProfile() directly awaits refresh(), and refresh() rethrows after recording
its error state. Other fire-and-forget refresh callers explicitly attach .catch(() => undefined),
whereas the newly added call does not.

apps/desktop/src/renderer/app-shell.tsx[3591-3595]
apps/desktop/src/renderer/use-new-task-target.ts[39-60]
apps/desktop/src/renderer/use-new-task-target.ts[63-67]
apps/desktop/src/renderer/use-new-task-target.ts[146-160]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The post-onboarding project-picker continuation can reject when catalog refresh fails, and its only caller discards that rejection.

## Issue Context
Reuse the renderer's existing fire-and-forget refresh pattern by attaching a rejection handler, or contain the error inside `chooseProjectForProfile()` while preserving its existing error state/toast behavior. New UI state or public API is unnecessary.

## Fix Focus Areas
- apps/desktop/src/renderer/app-shell.tsx[3591-3595]
- apps/desktop/src/renderer/use-new-task-target.ts[146-160]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Shutdown delays SSH termination ✓ Resolved 🐞 Bug ☼ Reliability
Description
Fix-now: closeRuntimeHostDesktop() waits for onboarding to close before calling
runtimeHostSshTerminal.close(), but onboarding deliberately does not abort after setup emits its
completion frame and instead awaits the setup task. If that SSH process remains alive, application
shutdown cannot terminate it until the setup path's ten-minute timeout expires.
Code

apps/desktop/src/main/runtime-host-boot.ts[1366]

+    runtimeHostOnboarding.close().then(() => runtimeHostSshTerminal.close()),
Relevance

●●● Strong

Recent accepted teardown fixes prevent long-lived stuck operations.

PR-#3111
PR-#3048

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Onboarding marks the operation non-cancellable at commit, and its close() only aborts cancellable
work before awaiting the task. The task waits on SSH with a ten-minute timeout, while the changed
shutdown line invokes the SSH close only after that wait resolves.

apps/desktop/src/main/runtime-host-boot.ts[1363-1367]
apps/desktop/src/main/runtime-host-onboarding.ts[73-80]
apps/desktop/src/main/runtime-host-onboarding.ts[153-160]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[317-321]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[35-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Desktop shutdown serializes onboarding closure before SSH-terminal closure. During the non-cancellable commit phase, onboarding waits for the SSH process, while the code capable of terminating that process cannot run.

## Issue Context
Reuse both existing `close()` seams as independent entries in the existing `Promise.allSettled` shutdown sequence rather than chaining them. No new state, branch, configuration, or public surface is required.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-boot.ts[1363-1367]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unknown finalize hangs forever ✗ Dismissed 🐞 Bug ☼ Reliability
Description
Fix-now: finalizePairing() classifies commit_outcome_unknown as retryable but then waits for a
replacement connection, even though that error can be returned over a still-healthy connection. With
no reconnect event, managed onboarding remains in connecting_host indefinitely and never completes
or fails.
Code

apps/desktop/src/main/runtime-host-desktop-manager.ts[R251-253]

+        const retry = pairingFinalizeRetry(error);
+        if (!retry) throw error;
+        candidate = await this.#waitForReadyCandidate(lifecycle, candidate);
Relevance

●●● Strong

Recent Runtime Host fixes require terminal outcomes rather than indefinite pending.

PR-#3048

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The server explicitly converts a post-publication persistence uncertainty into a
commit_outcome_unknown operation error without closing the connection. The manager then passes the
current candidate as previous, and waitForCurrent(previous) only resolves when a different
candidate appears, proving that a healthy unchanged connection leaves the promise pending.

packages/runtime-host/src/server/access-authority.ts[458-471]
apps/desktop/src/main/runtime-host-desktop-manager.ts[243-254]
apps/desktop/src/main/runtime-host-desktop-manager.ts[738-750]
packages/runtime-host/src/client/reconnect-lifecycle.ts[129-149]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A `commit_outcome_unknown` operation response does not imply connection loss, but finalization waits for a new reconnect candidate before retrying. If the connection stays healthy, onboarding hangs forever.

## Issue Context
Separate the two existing retry cases: a dispatched `connection_lost` error should wait for the reconnect lifecycle, while `commit_outcome_unknown` should retry idempotent finalization on the current candidate. No new public state or configuration is needed.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-desktop-manager.ts[243-253]
- apps/desktop/src/main/runtime-host-desktop-manager.ts[738-750]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (7)
4. Finalize failure strands replacement ✓ Resolved 🐞 Bug ☼ Reliability
Description
Fix-now: addAndEnableVerified() treats credential finalization as successful only after it has
already rebound and enabled the existing profile, but its failure path merely marks the replacement
unavailable and throws. A lost/failed finalize RPC can therefore make onboarding report failure
while the Desktop has discarded the prior saved credential and retains a pending credential that
later expires, leaving the previously usable Host disconnected until the user repeats setup.
Code

apps/desktop/src/main/runtime-host-profile-service.ts[R345-350]

+            await input.finalizePairing(profile.id);
+            unavailable.delete(profile.id);
+            return { profileId: profile.id };
+          } catch (error) {
+            unavailable.set(profile.id, asError(error));
+            throw error;
Relevance

●●● Strong

Recent reliability precedents accept preserving failure causes and transactional cleanup across
Runtime Host lifecycle boundaries.

PR-#2674
PR-#1755

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The replacement branch performs its rollback only around rebind, enable, and preference persistence;
finalization occurs afterward, outside that rollback. The authority accepts pending credentials only
until expiresAt, and finalize() can fail before changing the pending record to active, so a
failure at this point leaves the persisted candidate temporary while the prior Desktop credential
has already been overwritten.

apps/desktop/src/main/runtime-host-profile-service.ts[267-343]
apps/desktop/src/main/runtime-host-profile-service.ts[345-350]
packages/runtime-host/src/server/access-authority.ts[81-105]
packages/runtime-host/src/server/access-authority.ts[227-258]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A re-pair updates the existing Desktop profile and enables the candidate credential before finalization. If `finalizePairing` fails, the current code only records the failure, so the old saved credential has already been replaced while the candidate may remain pending and expire.

## Issue Context
Finalization is idempotent when the candidate is already active, but a persistence/RPC failure can leave it pending. Do not blindly restore the old profile without reconciling the remote finalization state, because a response may have been lost after the server committed.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-profile-service.ts[267-350]
- apps/desktop/src/main/runtime-host-desktop-manager.ts[234-245]
- packages/runtime-host/src/server/access-authority.ts[227-258]

Reconcile/retry the candidate finalization using the persisted candidate before reporting failure; if it is conclusively not finalized, restore the prior resolved profile/credential and manager target (or otherwise retain an explicit recoverable finalization state). Add a regression test for a re-pair whose finalization fails before server commit, asserting the existing profile remains usable rather than being left with an expiring pending credential.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Cancelled PTY can hang ✓ Resolved 🐞 Bug ☼ Reliability
Description
Fix-now: abort and the ten-minute timeout only send SIGTERM before awaiting process.exited
without forced termination or a rejection fallback. If SSH/SCP or its remote child does not exit,
onboarding remains active, later setup is prevented, and Cancel, application shutdown, and the
advertised setup timeout can all block indefinitely.
Code

apps/desktop/src/main/runtime-host-ssh-terminal.ts[R302-304]

+      const onAbort = () => process.kill('SIGTERM');
+      setupInput.signal?.addEventListener('abort', onAbort, { once: true });
+      const timeout = setTimeout(() => process.kill('SIGTERM'), SETUP_TIMEOUT_MS);
Relevance

●●● Strong

Unbounded PTY shutdown can block cancellation and shutdown; recent cleanup precedents favor explicit
termination handling.

PR-#3185

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Both setup SSH and development-archive SCP install cancellation or timeout callbacks that only send
SIGTERM, then await the PTY-backed exit promise without escalation or another bounded outcome. The
onboarding cancel and close handlers await the setup task, propagating the unbounded wait to UI
cancellation and shutdown, while the shared SSH tunnel implementation demonstrates a termination
policy for the same process abstraction that escalates to SIGKILL after two seconds.

apps/desktop/src/main/runtime-host-ssh-terminal.ts[302-324]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[447-462]
apps/desktop/src/main/runtime-host-onboarding.ts[135-152]
packages/runtime-host/src/client/ssh-tunnel.ts[26-33]
packages/runtime-host/src/client/ssh-tunnel.ts[165-189]
apps/desktop/src/main/runtime-host-boot.ts[1338-1344]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Setup cancellation and the ten-minute timeout can hang forever because both the setup SSH and development-archive SCP paths send only `SIGTERM` and then wait indefinitely for `process.exited`. A stuck process can retain the active setup, prevent later setup, and delay application shutdown.

## Issue Context
Reuse the existing process kill/exited seam and SSH tunnel termination policy: send `SIGTERM`, allow a bounded grace period, and then issue `SIGKILL` while awaiting the exit promise. Apply this to both setup SSH and development-archive SCP processes, and ensure timeout produces a terminal error; the additional timer and branch are necessary because `SIGTERM` is advisory and the current exit promise has no bounded alternative.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-ssh-terminal.ts[302-324]
- apps/desktop/src/main/runtime-host-ssh-terminal.ts[447-462]
- apps/desktop/src/main/__tests__/runtime-host-ssh-terminal.test.ts[66-168]
- packages/runtime-host/src/client/ssh-tunnel.ts[165-189]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Version hash omits manifest ✓ Resolved 🐞 Bug ≡ Correctness
Description
Fix-now: developmentPackageVersion hashes stageRoot before writeReleaseManifest creates
package.json, even though that generated manifest is part of the packed archive. Changes to
generated metadata such as bin, engines, or publish/package fields can therefore produce
different archives with the same supposedly content-addressed development version, defeating the
cache-busting purpose of the override.
Code

scripts/release-cli-package.mjs[R516-521]

+  for (const path of walkFiles(stageRoot)
+    .filter((candidate) => lstatSync(candidate).isFile())
+    .sort()) {
+    digest.update(relative(stageRoot, path).split(sep).join('/'));
+    digest.update('\0');
+    digest.update(readFileSync(path));
Relevance

●●● Strong

The generated manifest is archived but omitted from its content hash, violating the stated
cache-busting invariant.

PR-#3188

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The build calls writeReleaseManifest after all copy steps, and that function computes the
development version before writing stageRoot/package.json. The omitted file contains behaviorally
relevant package metadata copied from both the CLI and root manifests, while npm pack includes that
file in the archive.

scripts/release-cli-package.mjs[109-123]
scripts/release-cli-package.mjs[458-524]
packages/cli/package.json[2-27]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The development version digest excludes the generated root package.json, so it is not a digest of all package content.

## Issue Context
Consolidate manifest construction and hashing: construct the manifest without its self-referential version, hash that canonical metadata together with staged files, then assign the derived version and write it. This does not require a new public surface or configuration; it only changes the ordering of the existing authority.

## Fix Focus Areas
- scripts/release-cli-package.mjs[458-524]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Failed re-pair overwrites profile ✓ Resolved 🐞 Bug ≡ Correctness
Description
Fix-now: the existing-root branch saves the new name and credential before attempting the
connection, but its failure handler never restores the prior target. A failed re-pair therefore
loses the prior saved credential/name and can also replace a previously active manager target with
an unavailable one even though onboarding reports failure.
Code

apps/desktop/src/main/runtime-host-profile-service.ts[R267-269]

+          const profile = { ...existing, name: value.profile.name };
+          await catalog.save(profile, value.credential);
+          const target = await catalog.resolve(profile.id);
Relevance

●●● Strong

Persisting replacement credentials before connection without restoring the prior target is a clear
rollback correctness defect.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
catalog.save updates the profile and credential before input.enable; the catch only records an
unavailable error and rethrows. RuntimeHostDesktopManager removes an existing same-ID target when
its resolved target changes before attempting the replacement connection, so failure also tears down
the old active target.

apps/desktop/src/main/runtime-host-profile-service.ts[262-297]
packages/runtime-host/src/client/host-profile.ts[362-400]
apps/desktop/src/main/runtime-host-desktop-manager.ts[339-371]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Refreshing an existing Host mutates its persisted profile before connection succeeds and leaves that mutation in place on failure.

## Issue Context
Consolidate this branch with the transactional rollback authority already used for newly created verified profiles. Preserve the previous resolved target, and on failure restore its profile/credential and reconnect it if it was enabled; no new persistent state is needed.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-profile-service.ts[262-297]
- apps/desktop/src/main/runtime-host-profile-service.ts[316-328]
- apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts[249-277]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Setup cancellation still persists host ✗ Dismissed 🐞 Bug ≡ Correctness
Description
Cancelling after remote setup completes but while addAndEnableVerified() is connecting or
persisting the profile does not stop the operation, so it can still enable and save a remote Host
and publish complete after cancellation. The dialog therefore reports cancellation while leaving a
computer added that the user explicitly aborted.
Code

apps/desktop/src/main/runtime-host-onboarding.ts[R96-99]

+      const connected = await input.profiles.addAndEnableVerified({
+        profile: {
+          id: profileId,
+          name: profileName,
Relevance

●●● Strong

Cancellation must cover the profile transaction and prevent completion after abort; this is a direct
correctness gap.

PR-#3048

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The onboarding signal is passed to runSetup and checked before profile work, but it is neither
passed into the newly added addAndEnableVerified() operation nor checked before the successful
path publishes completion. Because the cancellation IPC waits for this same task, an abort arriving
during the profile-service call cannot prevent enablement and persistence; the profile service has
no abort boundary for this transaction, even though the existing remote connection seam supports
AbortSignal.

apps/desktop/src/main/runtime-host-onboarding.ts[71-87]
apps/desktop/src/main/runtime-host-onboarding.ts[96-123]
apps/desktop/src/main/runtime-host-profile-service.ts[259-329]
packages/runtime-host/src/client/host-profile.ts[153-235]
apps/desktop/src/main/runtime-host-onboarding.ts[87-116]
apps/desktop/src/main/runtime-host-onboarding.ts[135-140]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Cancellation is checked after SSH setup but not while the verified profile is being connected, enabled, and persisted. Cancelling during that interval can leave a newly added Host enabled and saved, then publish completion despite the user's cancellation.

## Issue Context
Make the profile verification path participate in the existing onboarding abort lifecycle. A check after `addAndEnableVerified()` alone is insufficient because connection and persistence have already occurred, so extend the operation's cancellation contract and reuse the profile service's existing rollback/removal seams to compensate for any newly created profile when cancellation wins.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-onboarding.ts[87-116]
- apps/desktop/src/main/runtime-host-profile-service.ts[259-329]
- apps/desktop/src/main/__tests__/runtime-host-onboarding.test.ts[7-60]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Orphaned pairing credentials ✓ Resolved 🐞 Bug ⛨ Security
Description
Switching setup from replace to issue leaves the candidate credential active after the CLI has
emitted complete; if Desktop then cannot connect, persist, or finalize the profile, nothing
revokes that candidate. Repeated failed onboarding attempts accumulate fully privileged remote-owner
credentials for the same Desktop principal until an eventual successful finalization, and the access
file retains them indefinitely.
Code

packages/cli/src/runtime-host-setup-command.ts[R159-161]

+  let paired: Awaited<ReturnType<typeof issueRuntimeHostAccessCredential>>;
  try {
-    paired = await deps.replaceCredential({
+    paired = await deps.issueCredential({
Relevance

●● Moderate

Security cleanup concern is plausible; PR actually adds revoke-on-failure, but a similar
transactional-cleanup ask was rejected once.

PR-#3230

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed setup path creates a non-replacing active credential, then only revokes it when the
CLI's own verification throws. The access authority persists issued credentials as active, while
Desktop's subsequent profile-connection rollback removes only the local catalog entry; it has no
credential ID in its setup result with which to invoke cleanup.

packages/cli/src/runtime-host-setup-command.ts[159-207]
packages/runtime-host/src/server/access-authority.ts[120-145]
apps/desktop/src/main/runtime-host-profile-service.ts[354-379]
apps/desktop/src/main/runtime-host-onboarding.ts[95-110]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`runtime-host setup` now issues a candidate credential rather than replacing the prior credential. After its successful local verification and completion frame, Desktop can still fail while connecting, saving, or finalizing; that candidate remains active because only verification failures invoke the existing revoke path.

## Issue Context
Reuse the existing credential-revocation seam rather than adding an independent credential store or authority. Preserve the successful-pairing behavior: the candidate must remain usable until Desktop verifies and finalizes it, but it must be revoked when the Desktop-side pairing attempt fails. If cleanup cannot be reached, introduce explicit bounded candidate lifecycle state/expiry only if reusing the existing revoke path cannot guarantee cleanup; document and test that new lifecycle burden.

## Fix Focus Areas
- packages/cli/src/runtime-host-setup-command.ts[159-207]
- apps/desktop/src/main/runtime-host-profile-service.ts[354-388]
- apps/desktop/src/main/runtime-host-onboarding.ts[75-110]
- packages/cli/src/runtime-host-access-command.ts[138-151]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. Stale credential revokes replacement ✓ Resolved 🐞 Bug ⛨ Security
Description
Fix-now: finalize() accepts any active credential and revokes every other active credential for
the same principal, so an older connection can finalize after a newer setup credential is issued and
invalidate that replacement. This breaks safe credential handoff and lets a stale or compromised
client prevent re-pairing.
Code

packages/runtime-host/src/server/access-authority.ts[R200-205]

+      const revoked = this.#file.credentials.filter(
+        (credential) =>
+          credential.credentialId !== credentialId &&
+          credential.status === 'active' &&
+          credential.principalKind === retained.principalKind &&
+          credential.principalId === retained.principalId,
Relevance

●● Moderate

Race condition is concrete but no closely matching accepted/rejected precedent establishes team's
stance on this exact issue.

PR-#3230

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Issued credentials are appended to the credential file, but finalization checks only that the caller
remains active and then selects all same-principal active siblings without considering issuance
order. The operation is available to remote owners and Desktop invokes it only after an asynchronous
connection wait, providing a concrete window for a newer credential to be issued before the stale
caller finalizes.

packages/runtime-host/src/server/access-authority.ts[96-169]
packages/runtime-host/src/server/access-authority.ts[192-219]
packages/runtime-host/src/protocol/operations.ts[200-206]
apps/desktop/src/main/runtime-host-desktop-manager.ts[234-245]
apps/desktop/src/main/runtime-host-profile-service.ts[344-350]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Credential finalization currently lets any active credential revoke all sibling credentials for its principal. Require the caller's credential to be the newest active issuance for that principal, and revoke only credentials that precede it.

## Issue Context
Reuse the access file's existing issuance ordering rather than adding a new protocol operation or public state: credentials are appended when issued. A stale credential must fail finalization if a later active credential for the same principal exists.

## Fix Focus Areas
- packages/runtime-host/src/server/access-authority.ts[192-219]
- packages/runtime-host/src/server/access-authority.ts[132-145]
- packages/runtime-host/src/__tests__/authenticated-websocket.test.ts[367-379]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

11. Stable version breaks CLI test 🐞 Bug ⚙ Maintainability ⭐ New
Description
Fix-now: the test now builds its fixture from the current CLI version but still hardcodes
dist_tag=next; when the manifest advances to a supported stable version, the command correctly
emits latest and this test fails. This makes a normal stable release require an unrelated test
rewrite.
Code

scripts/release-cli-publication.test.mjs[333]

+  const fixture = createCandidate(CURRENT_CLI_VERSION);
Relevance

●●● Strong

Clear deterministic test-fixture mismatch; recent accepted precedent favors eliminating brittle
future test failures.

PR-#3185
PR-#3188

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed fixture call uses CURRENT_CLI_VERSION, while the same assertion remains fixed to
dist_tag=next. The release parser explicitly maps versions without a prerelease component to
latest, and this test suite already asserts that stable versions are supported.

scripts/release-cli-publication.test.mjs[21-23]
scripts/release-cli-publication.test.mjs[332-358]
scripts/release-cli-publication.mjs[24-31]
scripts/release-cli-publication.test.mjs[25-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The prepare-stage CLI test uses the current package version but assumes that version is always a prerelease. A stable CLI version produces the valid `latest` distribution tag and causes the test to fail.

## Issue Context
Reuse the existing `parseCliReleaseVersion` seam to derive expected release identity. No new state, branch, configuration, or public surface is needed.

## Fix Focus Areas
- scripts/release-cli-publication.test.mjs[21-23]
- scripts/release-cli-publication.test.mjs[332-358]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. Build metadata package rejected ✓ Resolved 🐞 Bug ≡ Correctness
Description
runtimeHostSetupPackage() accepts exact package versions containing +, such as
maka-agent@1.2.3+build.1, but prepareSetupPackage() rejects the resulting specifier before SSH
setup runs. A Desktop manifest using valid SemVer build metadata therefore passes startup validation
but every Add computer attempt fails with “Runtime Host setup package is invalid.”
Code

apps/desktop/src/main/runtime-host-boot.ts[R325-327]

+    typeof specifier !== "string" ||
+    !/^maka-agent@[0-9][0-9A-Za-z.+-]*$/u.test(specifier)
+  ) {
Relevance

●●● Strong

Recent validation and protocol-boundary bugs are explicitly accepted; this is a deterministic
incompatible-regex correctness fix.

PR-#3230
PR-#3079

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The boot path accepts + and returns the specifier as an npm setup package, while the SSH
preparation path applies a narrower character class and throws before constructing the remote
command. These two validators govern the same value but define incompatible accepted sets.

apps/desktop/src/main/runtime-host-boot.ts[316-330]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[440-458]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[568-589]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Desktop manifest validator accepts `+` in an exact `maka-agent` version, while the SSH setup validator rejects it. This makes a package accepted at boot unusable during onboarding.

## Issue Context
Reuse one validator for both selection and setup-package preparation rather than adding another independent rule. The shared rule should accept the exact package-version syntax supported by the manifest contract, including SemVer build metadata.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-boot.ts[323-330]
- apps/desktop/src/main/runtime-host-ssh-terminal.ts[454-458]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. Failed setup leaves remote archive ✓ Resolved 🐞 Bug ☼ Reliability
Description
In unpackaged development mode, a successful SCP upload is cleaned up only by the subsequent remote
setup command. If SSH setup cannot start, is cancelled before launch, or cannot connect, that
command never runs and leaves the uploaded archive in the remote user's /tmp.
Code

apps/desktop/src/main/runtime-host-ssh-terminal.ts[R451-458]

+    const result = await process.exited;
+    signal?.throwIfAborted();
+    if (result.code !== 0) {
+      throw new Error(
+        `Uploading the Runtime Host development package exited with code ${String(result.code)}`,
+      );
+    }
+    return { specifier: remoteArchive, removeAfterSetup: remoteArchive };
Relevance

●●● Strong

Temporary remote artifacts should be cleaned on every failure path, not only after successful SSH
setup.

PR-#3185

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
After SCP succeeds, the uploaded path is returned for later cleanup. The only removal is embedded in
the SSH remote command, which is launched afterward; therefore failure before or during SSH launch
cannot execute it.

apps/desktop/src/main/runtime-host-ssh-terminal.ts[431-458]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[261-299]
apps/desktop/src/main/runtime-host-ssh-terminal.ts[486-489]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A development package uploaded to the remote temporary directory is removed only within the normal remote setup command. Failures between upload completion and that command leave the archive behind.

## Issue Context
This affects only the explicit unpackaged-development archive override, so it is non-blocking, but it violates the temporary-upload expectation and accumulates remote files after retries.

## Fix Focus Areas
- apps/desktop/src/main/runtime-host-ssh-terminal.ts[431-462]
- apps/desktop/src/main/runtime-host-ssh-terminal.ts[465-489]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: ⚖️ Balanced: This small push changes desktop shutdown ordering and suppresses an async UI failure, so its behavioral lifecycle effects merit a full review.

Grey Divider

Tip of the day
💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread apps/desktop/src/main/runtime-host-ssh-terminal.ts Outdated
Comment thread apps/desktop/src/main/runtime-host-profile-service.ts Outdated
Comment thread scripts/release-cli-package.mjs
Comment thread apps/desktop/src/main/runtime-host-onboarding.ts
@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from 710be23 to e04eb16 Compare August 19, 2026 06:21
@M4n5ter

M4n5ter commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

Comment thread packages/runtime-host/src/server/access-authority.ts
Comment thread packages/cli/src/runtime-host-setup-command.ts Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 56ff859

@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from 56ff859 to 9c4737a Compare August 19, 2026 07:24
@M4n5ter

M4n5ter commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

Comment thread apps/desktop/src/main/runtime-host-profile-service.ts Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit a654cba

@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from c4082fc to c4a54fd Compare August 19, 2026 08:49
@M4n5ter

M4n5ter commented Aug 19, 2026

Copy link
Copy Markdown
Member Author

/agentic_review

Comment thread apps/desktop/src/main/runtime-host-desktop-manager.ts Outdated
Comment thread apps/desktop/src/main/runtime-host-boot.ts Outdated
Comment thread apps/desktop/src/renderer/app-shell.tsx Outdated
@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 37ec416

@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from 49996da to b2543c8 Compare August 19, 2026 10:14
@M4n5ter
M4n5ter marked this pull request as ready for review August 19, 2026 10:18

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (8)
packages/cli/src/runtime-host-cli.ts (1)

184-208: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Make allowConfiguration default explicit.

allowConfiguration is optional and the guard tests === false. A caller that omits the field gets configuration arguments enabled. parseSetupCommand relies on that implicit default, while parseServiceManagementCommand passes the value explicitly. A future caller that forgets the field silently accepts --root, --project-root, --websocket-port, and --websocket-path.

Disposition: optional. Destructure with a default so the intent is stated at one place.

♻️ Proposed refactor
 function parseManagedServiceOptions(
   argv: string[],
-  input: {
+  {
+    valueOptions,
+    flagOptions,
+    allowConfiguration = true,
+  }: {
     readonly valueOptions?: Readonly<Record<string, (value: string) => RuntimeHostCliError | void>>;
     readonly flagOptions?: Readonly<Record<string, () => RuntimeHostCliError | void>>;
     readonly allowConfiguration?: boolean;
   } = {},
 ): ManagedServiceOptions | RuntimeHostCliError {

Then use flagOptions, valueOptions, and if (!allowConfiguration) in the loop.

packages/cli/src/__tests__/runtime-host-service-manager.test.ts (1)

89-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add coverage for the duplicate --defer-pairing-commit branch.

parseSetupCommand in packages/cli/src/runtime-host-cli.ts (Line 127) returns Duplicate --defer-pairing-commit when the flag repeats. This test only covers the single-use case. The rejection branch has no assertion here.

Disposition: optional. Add one case that passes the flag twice and asserts the error result.

packages/runtime-host/src/server/operation-dispatcher.ts (1)

239-277: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: collapse the five identical unavailable handlers.

Every entry returns the same outcome. A single factory removes the repetition and keeps the Pick type check intact.

♻️ Proposed refactor
+const accessCredentialsUnavailable = async () => ({
+  ok: false as const,
+  error: {
+    code: 'operation_unavailable' as const,
+    message: 'Runtime Host access credentials are unavailable',
+  },
+});
+
 export function createUnavailableAccessAuthorityOperationHandlers(): AccessAuthorityOperationHandlerMap {
   return {
-    'access.credential.issue': async () => ({ ... }),
-    'access.credential.replace': async () => ({ ... }),
-    'access.credential.prepare': async () => ({ ... }),
-    'access.credential.revoke': async () => ({ ... }),
-    'access.credential.finalize': async () => ({ ... }),
+    'access.credential.issue': accessCredentialsUnavailable,
+    'access.credential.replace': accessCredentialsUnavailable,
+    'access.credential.prepare': accessCredentialsUnavailable,
+    'access.credential.revoke': accessCredentialsUnavailable,
+    'access.credential.finalize': accessCredentialsUnavailable,
   };
 }

Disposition: optional.

Source: Path instructions

packages/runtime-host/src/__tests__/host-profile.test.ts (1)

170-196: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the credential-only rebind path.

The test only exercises bindingChanged === true (the transport URL changes). The bindingChanged === false branch in rebindIfCurrent behaves differently: it reuses the same credential slot, sets displacedCredential to target.credential, and skips the credentials.delete(stored) step. That branch is unverified.

The profile.id/profile.rootId guard rejection is also unverified.

💚 Suggested additional assertions
+  test('rebinds a credential without changing the transport binding', async () => {
+    const path = await profilePath();
+    const credentials = memoryCredentials();
+    const desktop = createFileRuntimeHostProfileCatalog(path, credentials);
+    const profile = remoteProfile('office', 'wss://host.example.com', ROOT_A);
+    await desktop.create(profile, 'old-token');
+    const expected = await desktop.resolve(profile.id);
+    assert.equal((await desktop.rebindIfCurrent(expected, profile, 'new-token')).rebound, true);
+    assert.equal((await desktop.resolve(profile.id)).credential, 'new-token');
+  });
+
+  test('rejects a rebind that changes the Host identity', async () => {
+    const path = await profilePath();
+    const credentials = memoryCredentials();
+    const desktop = createFileRuntimeHostProfileCatalog(path, credentials);
+    const profile = remoteProfile('office', 'wss://host.example.com', ROOT_A);
+    await desktop.create(profile, 'old-token');
+    const expected = await desktop.resolve(profile.id);
+    await assert.rejects(
+      desktop.rebindIfCurrent(expected, remoteProfile('office', 'wss://host.example.com', ROOT_B), 'x'),
+      /must retain its Host identity/,
+    );
+  });

Disposition: follow-up.

Source: Path instructions

packages/cli/src/runtime-host-access-command.ts (1)

79-85: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: give the exported functions explicit, consistent signatures.

Two small inconsistencies in the new public surface:

  • Line 79: replaceRuntimeHostAccessCredential is async but only forwards a promise, while issueRuntimeHostAccessCredential and prepareRuntimeHostAccessCredential are not async.
  • Line 146: revokeRuntimeHostAccessCredential has no declared return type. runtime-host-setup-command.ts binds to it through typeof, so the exported contract is inferred from connection.request internals.
♻️ Proposed change
-export async function replaceRuntimeHostAccessCredential(
+export function replaceRuntimeHostAccessCredential(
   options: RuntimeHostAccessIssueOptions,
 ): Promise<ReplacedRuntimeHostAccessCredential> {
   return mutateRuntimeHostAccessCredential(options, 'access.credential.replace');
 }
-export async function revokeRuntimeHostAccessCredential(options: RuntimeHostAccessRevokeOptions) {
+export async function revokeRuntimeHostAccessCredential(
+  options: RuntimeHostAccessRevokeOptions,
+): Promise<OperationOutput<'access.credential.revoke'>> {

Disposition: optional.

Also applies to: 146-146

Source: Path instructions

packages/cli/src/runtime-host-managed-deployment.ts (1)

219-240: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Pass versionsRoot explicitly to pruneInactiveDevelopmentPackages. This avoids recomputing it with dirname(packageRoot) and removes unnecessary indirection.

Source: Path instructions

apps/desktop/src/main/__tests__/runtime-host-ssh-terminal.test.ts (1)

181-181: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Delete the shell-variable-name assertion.

assert.doesNotMatch(remoteCommand, /\bstatus=/u) asserts the internal name of a shell variable in the generated command. That name has no observable effect. The adjacent assertion on /maka_setup_exit/u already covers the exit-code propagation contract. A rename would break this test without any behavior change.

🧹 Suggested removal
   assert.match(remoteCommand, /maka_setup_exit/u);
-  assert.doesNotMatch(remoteCommand, /\bstatus=/u);

As per path instructions: "Flag tests that duplicate existing coverage, assert implementation details, or do not protect observable behavior."

Source: Path instructions

apps/desktop/src/main/__tests__/runtime-host-onboarding.test.ts (1)

62-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the cancellable path and for endpoint rejection.

The tests cover the non-cancellable commit phase and the success path. Two behaviors in runtime-host-onboarding.ts remain untested: cancel during the SSH phase returns true and publishes idle, and requireSetupEndpoint rejects a non-loopback or non-ws: endpoint. Both are security-relevant guards.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 35a99f27-6640-4c0a-9bbf-fdc85c2bf176

📥 Commits

Reviewing files that changed from the base of the PR and between b03b85e and b2543c8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (56)
  • CONTRIBUTING.md
  • CONTRIBUTING.zh-CN.md
  • apps/desktop/electron-builder.config.mjs
  • apps/desktop/src/main/__tests__/runtime-host-desktop-manager.test.ts
  • apps/desktop/src/main/__tests__/runtime-host-onboarding.test.ts
  • apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
  • apps/desktop/src/main/__tests__/runtime-host-ssh-terminal.test.ts
  • apps/desktop/src/main/runtime-host-boot.ts
  • apps/desktop/src/main/runtime-host-client.ts
  • apps/desktop/src/main/runtime-host-desktop-manager.ts
  • apps/desktop/src/main/runtime-host-onboarding.ts
  • apps/desktop/src/main/runtime-host-profile-service.ts
  • apps/desktop/src/main/runtime-host-ssh-terminal.ts
  • apps/desktop/src/preload/bridge-contract.d.ts
  • apps/desktop/src/preload/preload.ts
  • apps/desktop/src/renderer/app-shell-overlays.tsx
  • apps/desktop/src/renderer/app-shell.tsx
  • apps/desktop/src/renderer/locales/settings-projects-copy.ts
  • apps/desktop/src/renderer/settings/projects-settings-page.tsx
  • apps/desktop/src/renderer/settings/runtime-host-onboarding-dialog.tsx
  • apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
  • apps/desktop/src/renderer/settings/settings-modal.tsx
  • apps/desktop/src/renderer/settings/settings-surface.tsx
  • apps/desktop/src/renderer/styles/settings/runtime-host.css
  • apps/desktop/src/renderer/use-new-task-target.ts
  • apps/desktop/stories/settings/settings-pages.stories.tsx
  • docs/astryx-surface-file-inventory.md
  • docs/astryx-surface-file-inventory.paths
  • docs/runtime-host-remote-access.md
  • docs/runtime-host-remote-access.zh-CN.md
  • packages/cli/package.json
  • packages/cli/src/__tests__/runtime-host-cli-context.test.ts
  • packages/cli/src/__tests__/runtime-host-operator-command.test.ts
  • packages/cli/src/__tests__/runtime-host-profile-command.test.ts
  • packages/cli/src/__tests__/runtime-host-service-manager.test.ts
  • packages/cli/src/__tests__/runtime-host-setup.test.ts
  • packages/cli/src/cli-core.ts
  • packages/cli/src/runtime-host-access-command.ts
  • packages/cli/src/runtime-host-cli.ts
  • packages/cli/src/runtime-host-managed-deployment.ts
  • packages/cli/src/runtime-host-setup-command.ts
  • packages/cli/src/runtime-host-systemd-service.ts
  • packages/runtime-host/src/__tests__/authenticated-websocket.test.ts
  • packages/runtime-host/src/__tests__/host-profile.test.ts
  • packages/runtime-host/src/__tests__/websocket-listener.test.ts
  • packages/runtime-host/src/client/host-profile.ts
  • packages/runtime-host/src/protocol/access-authority.ts
  • packages/runtime-host/src/protocol/index.ts
  • packages/runtime-host/src/protocol/operations.ts
  • packages/runtime-host/src/server/access-authority.ts
  • packages/runtime-host/src/server/access-credential-store.ts
  • packages/runtime-host/src/server/connection-session.ts
  • packages/runtime-host/src/server/host-kernel.ts
  • packages/runtime-host/src/server/operation-dispatcher.ts
  • scripts/release-cli-package.mjs
  • scripts/release-cli-publication.test.mjs

Included review availability: Your plan provides up to 3 included reviews per hour; 1 remains after this review.

Comment thread apps/desktop/src/main/runtime-host-ssh-terminal.ts
Comment thread apps/desktop/src/preload/bridge-contract.d.ts
Comment thread apps/desktop/src/renderer/app-shell.tsx
Comment thread packages/runtime-host/src/server/access-authority.ts Outdated
Comment thread scripts/release-cli-package.mjs
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add managed remote Runtime Host onboarding to Desktop

✨ Enhancement 🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Adds one-destination SSH onboarding for installing, pairing, verifying, and connecting Linux
 Runtime Hosts.
• Makes credential handoff transactional and keeps secrets within Desktop’s main process.
• Supports content-addressed development archives and opens remote Project selection after setup.
Diagram

sequenceDiagram
  actor U as User
  participant R as Onboarding UI
  participant M as Desktop Main
  participant S as SSH Terminal
  participant C as Remote CLI
  participant H as Runtime Host
  participant P as Profile Manager
  participant J as Project Picker
  U->>R: Enter SSH target
  R->>M: Start onboarding
  M->>S: Run managed setup
  S->>C: Upload or fetch package
  C->>H: Install and prepare pairing
  H-->>C: Pending credential
  C-->>S: Setup progress frames
  S-->>M: Verified setup result
  M->>P: Persist and connect profile
  P->>H: Finalize authenticated pairing
  H-->>P: Activate new credential
  P-->>M: Profile ready
  M-->>R: Complete with profile ID
  R->>J: Open remote Project picker
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Implement setup directly in Desktop
  • ➕ Could tailor every installation step and error message to the Desktop UI.
  • ➕ Would avoid requiring the remote release CLI to expose a setup contract.
  • ➖ Duplicates service installation, deployment, and credential logic already owned by the CLI.
  • ➖ Expands Desktop’s security-sensitive SSH scripting and creates behavior drift between setup paths.
2. Deploy a persistent bootstrap agent
  • ➕ Could provide richer progress reporting and future remote management operations.
  • ➕ Would reduce repeated shell orchestration after initial installation.
  • ➖ Introduces another privileged lifecycle, protocol, and update surface on remote machines.
  • ➖ Requires users to preinstall or trust an additional service before onboarding.

Recommendation: Keep the PR’s approach: reuse the released CLI setup contract over interactive SSH, stage credential replacement, and finalize only through the verified Desktop connection. This minimizes duplicated installation logic, keeps secrets out of the renderer, and preserves manual profiles for unsupported endpoints; a persistent bootstrap agent is not justified for this onboarding scope.

Files changed (57) +2692 / -163

Enhancement (25) +1305 / -60
runtime-host-boot.tsWire managed onboarding into Desktop startup +44/-1

Wire managed onboarding into Desktop startup

• Creates the onboarding service, selects an exact release package or development archive, delegates pairing finalization, and closes onboarding during shutdown.

apps/desktop/src/main/runtime-host-boot.ts

runtime-host-client.tsExpose credential finalization on Host clients +4/-0

Expose credential finalization on Host clients

• Adds a typed client method for the new access credential finalization operation.

apps/desktop/src/main/runtime-host-client.ts

runtime-host-onboarding.tsAdd main-process onboarding coordinator +203/-0

Add main-process onboarding coordinator

• Adds validated IPC state management for starting, monitoring, cancelling, and resetting SSH onboarding. It persists verified profiles while keeping credentials out of renderer snapshots.

apps/desktop/src/main/runtime-host-onboarding.ts

runtime-host-ssh-terminal.tsRun managed setup over bounded SSH +448/-32

Run managed setup over bounded SSH

• Runs exact CLI setup packages through interactive SSH, optionally uploads development archives, parses hidden setup frames, and bounds cancellation and timeout termination. Setup becomes non-cancellable after the completion frame commits.

apps/desktop/src/main/runtime-host-ssh-terminal.ts

bridge-contract.d.tsDefine the onboarding bridge contract +41/-0

Define the onboarding bridge contract

• Adds onboarding input, phase, snapshot, command, and subscription types to the renderer bridge.

apps/desktop/src/preload/bridge-contract.d.ts

preload.tsExpose onboarding IPC to the renderer +24/-0

Expose onboarding IPC to the renderer

• Adds preload methods for onboarding snapshots, start, cancel, reset, and change subscriptions.

apps/desktop/src/preload/preload.ts

app-shell-overlays.tsxRoute remote Host completion through overlays +2/-0

Route remote Host completion through overlays

• Passes the newly added remote profile callback into the settings modal.

apps/desktop/src/renderer/app-shell-overlays.tsx

app-shell.tsxOpen Project selection after onboarding +5/-0

Open Project selection after onboarding

• Closes settings, opens the new-task surface, and selects the newly connected Host for remote Project selection.

apps/desktop/src/renderer/app-shell.tsx

settings-projects-copy.tsAdd bilingual onboarding copy +57/-2

Add bilingual onboarding copy

• Adds English and Simplified Chinese labels for managed setup controls, progress phases, completion, and manual configuration.

apps/desktop/src/renderer/locales/settings-projects-copy.ts

projects-settings-page.tsxConnect settings to onboarding completion +3/-2

Connect settings to onboarding completion

• Passes the remote Host completion callback into the Runtime Host profiles section in both availability states.

apps/desktop/src/renderer/settings/projects-settings-page.tsx

runtime-host-onboarding-dialog.tsxAdd the remote computer onboarding dialog +193/-0

Add the remote computer onboarding dialog

• Provides SSH destination and port inputs, live setup phases, cancellation and retry handling, and completion actions for choosing a remote Project.

apps/desktop/src/renderer/settings/runtime-host-onboarding-dialog.tsx

runtime-host-profiles-section.tsxAdd managed and manual Host actions +29/-8

Add managed and manual Host actions

• Introduces a primary Add computer flow while retaining manual profile configuration for advanced endpoints. Reloads profiles after onboarding and forwards Project selection.

apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx

settings-modal.tsxForward remote Host completion from settings +2/-0

Forward remote Host completion from settings

• Adds and forwards the remote Host completion callback through the settings modal.

apps/desktop/src/renderer/settings/settings-modal.tsx

settings-surface.tsxPropagate onboarding completion through settings +4/-0

Propagate onboarding completion through settings

• Threads the remote Host completion callback through the settings surface and Projects page.

apps/desktop/src/renderer/settings/settings-surface.tsx

runtime-host.cssStyle onboarding progress and actions +8/-0

Style onboarding progress and actions

• Adds spacing for multi-button terminal actions and lays out the managed setup progress indicator.

apps/desktop/src/renderer/styles/settings/runtime-host.css

use-new-task-target.tsSelect a newly connected Host +17/-0

Select a newly connected Host

• Refreshes the Host catalog, selects the ready profile, and opens its directory picker or reports unavailable state.

apps/desktop/src/renderer/use-new-task-target.ts

cli-core.tsForward deferred pairing into setup +1/-0

Forward deferred pairing into setup

• Passes the parsed deferred pairing option into the Runtime Host setup command.

packages/cli/src/cli-core.ts

runtime-host-cli.tsParse deferred pairing setup mode +36/-15

Parse deferred pairing setup mode

• Adds the defer-pairing-commit flag and refactors managed service option parsing to support value and boolean extensions.

packages/cli/src/runtime-host-cli.ts

runtime-host-managed-deployment.tsManage content-addressed development deployments +23/-0

Manage content-addressed development deployments

• Recognizes development package versions, adds deployment commit handling, and prunes superseded development versions after successful setup.

packages/cli/src/runtime-host-managed-deployment.ts

host-profile.tsAdd conditional Host profile rebinding +84/-0

Add conditional Host profile rebinding

• Atomically updates a profile transport and credential only when its expected profile and secret remain current, with rollback across file and credential stores.

packages/runtime-host/src/client/host-profile.ts

access-authority.tsDefine staged pairing protocol operations +40/-0

Define staged pairing protocol operations

• Adds credential prepare and finalize operations, strict payload decoding, and an explicit unknown commit outcome error.

packages/runtime-host/src/protocol/access-authority.ts

operations.tsAllow remote owners to finalize pairing +1/-0

Allow remote owners to finalize pairing

• Grants remote-owner credentials access to the narrowly scoped credential finalization operation.

packages/runtime-host/src/protocol/operations.ts

connection-session.tsAttach credentials to operation context +3/-0

Attach credentials to operation context

• Projects the authenticated credential identifier into dispatch context so finalization applies to the calling credential.

packages/runtime-host/src/server/connection-session.ts

host-kernel.tsDispatch and close staged access authority +18/-0

Dispatch and close staged access authority

• Registers credential prepare and finalize handlers, drains after uncertain commits, and closes the authority across startup failure and shutdown paths.

packages/runtime-host/src/server/host-kernel.ts

operation-dispatcher.tsExtend access operation dispatch context +15/-0

Extend access operation dispatch context

• Adds the authenticated credential identifier and unavailable handlers for credential preparation and finalization.

packages/runtime-host/src/server/operation-dispatcher.ts

Bug fix (6) +482 / -42
runtime-host-desktop-manager.tsFinalize pairing through the connected profile +42/-1

Finalize pairing through the connected profile

• Finalizes staged credentials over the authenticated remote connection and retries only when dispatch or commit outcomes are uncertain.

apps/desktop/src/main/runtime-host-desktop-manager.ts

runtime-host-profile-service.tsPersist managed profiles transactionally +140/-0

Persist managed profiles transactionally

• Adds verified profile creation and same-Host rebinding with connection checks, pairing finalization, and rollback of profiles, credentials, preferences, and enabled connections.

apps/desktop/src/main/runtime-host-profile-service.ts

runtime-host-setup-command.tsStage and verify setup credentials +51/-16

Stage and verify setup credentials

• Optionally prepares a pending credential, verifies it before reporting completion, revokes failed candidates, and commits successful deployments. Development versions may replace one another through the setup path.

packages/cli/src/runtime-host-setup-command.ts

runtime-host-systemd-service.tsKeep managed Hosts continuously running +1/-1

Keep managed Hosts continuously running

• Changes the systemd restart policy from failure-only to always, preserving service availability after clean exits.

packages/cli/src/runtime-host-systemd-service.ts

access-authority.tsImplement expiring staged credentials +218/-22

Implement expiring staged credentials

• Adds pending credential preparation, authenticated idempotent finalization, prior credential revocation, expiry scheduling, and authority shutdown. Persistence ambiguity is surfaced separately for safe client retry.

packages/runtime-host/src/server/access-authority.ts

access-credential-store.tsPersist pending credential state safely +30/-2

Persist pending credential state safely

• Extends stored credentials with pending status and expiry validation. Detects durability failures after publication so finalization can report an unknown commit outcome.

packages/runtime-host/src/server/access-credential-store.ts

Refactor (1) +36 / -27
runtime-host-access-command.tsGeneralize credential mutation helpers +36/-27

Generalize credential mutation helpers

• Extracts reusable issue, prepare, replace, and revoke helpers so managed setup can stage and roll back pairing credentials.

packages/cli/src/runtime-host-access-command.ts

Tests (14) +801 / -28
runtime-host-desktop-manager.test.tsTest pairing finalization retries +76/-0

Test pairing finalization retries

• Covers replay after an unknown finalization outcome and verifies that commands rejected before dispatch are not replayed.

apps/desktop/src/main/tests/runtime-host-desktop-manager.test.ts

runtime-host-onboarding.test.tsTest managed onboarding orchestration +127/-0

Test managed onboarding orchestration

• Verifies profile creation without renderer credential exposure and ensures cancellation is fenced once pairing commit begins.

apps/desktop/src/main/tests/runtime-host-onboarding.test.ts

runtime-host-profile-service.test.tsTest transactional managed profile persistence +148/-0

Test transactional managed profile persistence

• Covers failed profile cleanup, same-Host rebinding, pairing finalization, and restoration of previous profiles after connection or finalization failures.

apps/desktop/src/main/tests/runtime-host-profile-service.test.ts

runtime-host-ssh-terminal.test.tsTest secure and bounded SSH setup +170/-4

Test secure and bounded SSH setup

• Tests setup-frame filtering, credential secrecy, forced process termination, and development archive upload and reuse.

apps/desktop/src/main/tests/runtime-host-ssh-terminal.test.ts

settings-pages.stories.tsxUpdate settings story callback contract +1/-0

Update settings story callback contract

• Supplies the new remote Host completion callback in the settings story harness.

apps/desktop/stories/settings/settings-pages.stories.tsx

runtime-host-cli-context.test.tsUpdate profile catalog test double +3/-0

Update profile catalog test double

• Adds the conditional rebind method required by the expanded profile catalog contract.

packages/cli/src/tests/runtime-host-cli-context.test.ts

runtime-host-operator-command.test.tsTest credential preparation grants +2/-0

Test credential preparation grants

• Verifies that ordinary remote credentials cannot prepare credentials while local operators receive the new authority.

packages/cli/src/tests/runtime-host-operator-command.test.ts

runtime-host-profile-command.test.tsUpdate profile command test catalog +1/-0

Update profile command test catalog

• Adds a failing rebind stub to ensure profile commands do not unexpectedly use the new mutation path.

packages/cli/src/tests/runtime-host-profile-command.test.ts

runtime-host-service-manager.test.tsTest deferred pairing and service restart policy +3/-0

Test deferred pairing and service restart policy

• Covers parsing the deferred commit flag and verifies managed systemd services always restart.

packages/cli/src/tests/runtime-host-service-manager.test.ts

runtime-host-setup.test.tsTest staged setup and development replacement +99/-3

Test staged setup and development replacement

• Tests candidate revocation after verification failure and safe replacement and pruning of content-addressed development deployments.

packages/cli/src/tests/runtime-host-setup.test.ts

authenticated-websocket.test.tsTest transactional credential pairing +135/-18

Test transactional credential pairing

• Exercises pending credential authentication and idempotent finalization, old credential revocation, expiry cleanup, and safe access-authority shutdown.

packages/runtime-host/src/tests/authenticated-websocket.test.ts

host-profile.test.tsTest conditional profile rebinding +28/-0

Test conditional profile rebinding

• Verifies atomic transport and credential rebinding and rejects stale mutations after concurrent profile changes.

packages/runtime-host/src/tests/host-profile.test.ts

websocket-listener.test.tsUpdate access authority test contract +3/-0

Update access authority test contract

• Adds preparation, finalization, and closure stubs to the WebSocket listener authority fixture.

packages/runtime-host/src/tests/websocket-listener.test.ts

release-cli-publication.test.mjsAlign publication fixtures with the CLI version +5/-3

Align publication fixtures with the CLI version

• Uses the current CLI manifest version where the publication workflow requires exact package metadata while retaining overridable fixtures.

scripts/release-cli-publication.test.mjs

Documentation (6) +29 / -3
CONTRIBUTING.mdDocument development archive onboarding +10/-0

Document development archive onboarding

• Documents how to build a release-shaped CLI archive and use it for Desktop remote setup testing. Clarifies that packaged builds ignore the development override.

CONTRIBUTING.md

CONTRIBUTING.zh-CN.mdDocument development onboarding in Chinese +10/-0

Document development onboarding in Chinese

• Adds the Chinese instructions for building and uploading a worktree CLI archive during Desktop development.

CONTRIBUTING.zh-CN.md

astryx-surface-file-inventory.mdRegister the onboarding design surface +2/-1

Register the onboarding design surface

• Adds the onboarding dialog to the Astryx inventory and updates aligned file totals.

docs/astryx-surface-file-inventory.md

astryx-surface-file-inventory.pathsTrack the onboarding dialog path +1/-0

Track the onboarding dialog path

• Adds the new settings dialog to the generated design-surface path inventory.

docs/astryx-surface-file-inventory.paths

runtime-host-remote-access.mdDocument managed Desktop connection setup +3/-1

Document managed Desktop connection setup

• Replaces the manual-first instructions with Add computer onboarding and identifies manual configuration as the advanced endpoint path.

docs/runtime-host-remote-access.md

runtime-host-remote-access.zh-CN.mdDocument managed setup in Chinese +3/-1

Document managed setup in Chinese

• Updates the Chinese remote access guide for SSH onboarding and retained manual endpoint configuration.

docs/runtime-host-remote-access.zh-CN.md

Other (5) +39 / -3
electron-builder.config.mjsPin packaged onboarding to the CLI release +16/-0

Pin packaged onboarding to the CLI release

• Validates the CLI package identity during Desktop packaging and embeds its exact package specifier in application metadata.

apps/desktop/electron-builder.config.mjs

package-lock.jsonLock CLI beta version update +1/-1

Lock CLI beta version update

• Updates the workspace lock entry for Maka CLI 0.1.0-beta.2.

package-lock.json

package.jsonBump the CLI beta release +1/-1

Bump the CLI beta release

• Advances the CLI package version to 0.1.0-beta.2 for the onboarding-compatible release.

packages/cli/package.json

index.tsAdvance Runtime Host compatibility epoch +1/-1

Advance Runtime Host compatibility epoch

• Bumps the compatibility epoch for the new credential pairing protocol requirements.

packages/runtime-host/src/protocol/index.ts

release-cli-package.mjsContent-address development CLI packages +20/-0

Content-address development CLI packages

• Derives non-publishable package versions from staged file and manifest content so development archives can be replaced and identified safely.

scripts/release-cli-package.mjs

@qodo-code-review

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit b2543c8

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the substantial hardening here. The current head is green and the supplied screenshot covers the new connection flow, but two P2 correctness gaps remain: generated development archives are not recognized by the new version predicate, and a process exit after durable profile mutation but before credential finalization leaves pairing unrecoverable. The final substantive commit also needs the declared Codex Generated-by trailer. Please address these items, then request an exact-head rereview. Because this changes user-visible behavior, a public protocol, credential security, and release behavior, independent human review is still required by project policy.

Reviewed with Codex as an AI-assisted code review. I verified the current diff, relevant authority boundaries, tests, CI, screenshot, and commit provenance; no external model output was used.

中文说明

当前 head 的 CI 和截图都没有问题,但仍有两个 P2:新生成的 dev 版本与识别正则不一致;Profile 已持久化但 credential 尚未 finalize 时如果进程退出,重启后无法恢复,旧 Profile 甚至会丢失可用凭证。最后一个实质性 commit 还缺少已声明的 Codex Generated-by trailer。修复后请按新 head 重新 review;同时本 PR 涉及 UI、公开协议、credential security 和 release 行为,仍需独立人工审查。

Comment thread packages/cli/src/runtime-host-managed-deployment.ts Outdated
Comment thread apps/desktop/src/main/runtime-host-profile-service.ts Outdated

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An independent adversarial pass confirmed the two earlier P2 findings and found one additional user-visible cancellation gap, inline below. The rest of the prior review remains unchanged.

中文说明

独立交叉复核确认了前两个 P2,并额外发现一个用户可见的取消路径问题,见下面 inline。此前其余结论不变。

Comment thread apps/desktop/src/main/runtime-host-ssh-terminal.ts
@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from 5f6bb39 to 0673602 Compare August 19, 2026 12:51

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts (1)

336-359: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that rollback restores the previous enablement state.

The test verifies the credential is restored and the journal is cleared. It does not verify the intent.wasEnabled branch in rollbackPairingIntent at apps/desktop/src/main/runtime-host-profile-service.ts Lines 339-354. stageInterruptedPairing enables PROFILE.id, so rollback must re-add it to enabledRemoteProfileIds and call input.enable with the restored target.

Both effects can regress without failing this test. Add assertions on the persisted preferences and on the re-enable call.

💚 Sketch of the added assertions
   const service = createDesktopRuntimeHostProfileService({
     clientDataRoot: root,
     startup,
     catalog,
     states: () => [connectingLocal()],
     enable: async (target) => {
+      enabled.push(target.credential ?? "");
       if (target.credential === "new-token") {
         throw new RuntimeHostPermanentReconnectError("pairing credential expired");
       }
     },
   assert.equal((await catalog.resolve(PROFILE.id)).credential, "old-token");
+  assert.deepEqual(enabled, ["new-token", "old-token"]);
+  const restored = await resolveDesktopRuntimeHostStartup(root, { catalog });
+  assert.deepEqual(restored.preferences.enabledRemoteProfileIds, [PROFILE.id]);
-  assert.equal((await resolveDesktopRuntimeHostStartup(root, { catalog })).pairingIntents.length, 0);
+  assert.equal(restored.pairingIntents.length, 0);

Declare const enabled: string[] = []; above the service.

packages/cli/src/__tests__/runtime-host-setup.test.ts (1)

178-179: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the dot-separated development version.

The packager emits 0.1.0-beta.2.dev-<hex> when the base version contains -. Add a fixture with this form to cover the \. branch in isRuntimeHostDevelopmentPackageVersion during replacement and pruning.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0487ef76-0312-44fe-bf07-5d8dfceca9c6

📥 Commits

Reviewing files that changed from the base of the PR and between 5f6bb39 and 0673602.

📒 Files selected for processing (13)
  • apps/desktop/src/main/__tests__/runtime-host-onboarding.test.ts
  • apps/desktop/src/main/__tests__/runtime-host-profile-service.test.ts
  • apps/desktop/src/main/__tests__/runtime-host-ssh-terminal.test.ts
  • apps/desktop/src/main/runtime-host-boot.ts
  • apps/desktop/src/main/runtime-host-onboarding.ts
  • apps/desktop/src/main/runtime-host-pairing-journal.ts
  • apps/desktop/src/main/runtime-host-profile-service.ts
  • apps/desktop/src/main/runtime-host-ssh-terminal.ts
  • apps/desktop/src/preload/bridge-contract.d.ts
  • apps/desktop/src/renderer/settings/runtime-host-ssh-terminal-dialog.tsx
  • packages/cli/src/__tests__/runtime-host-setup.test.ts
  • packages/cli/src/runtime-host-managed-deployment.ts
  • packages/runtime-host/src/client/index.ts

Included review availability: Your plan provides up to 3 included reviews per hour; 2 remain after this review.

Comment thread apps/desktop/src/main/runtime-host-pairing-journal.ts
Comment thread apps/desktop/src/main/runtime-host-pairing-journal.ts

@Astro-Han Astro-Han left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 06736029a2e6e78cb51153c39768423efec8259c.

The earlier development-version and crash-window pairing findings are fixed: the generated and recognized dev-<digest> grammar is aligned, and Desktop now persists a bounded atomic pairing journal before profile mutation, replays enable plus idempotent finalization after restart, and restores the previous credential after a permanent failure. The requested screenshot and all ten Codex trailers are present, and all prior threads are resolved.

One current-main integration blocker remains inline. Please rebase, advance the compatibility epoch, update fixtures, and rerun the still-pending current-base checks. Independent human review remains required because this affects UI, a public protocol, credential security, and release behavior.

AI-assisted review disclosure: Codex reviewed the exact-head delta, prior findings and remediation, recovery tests, current-main protocol integration, live threads and CI, screenshot, and provenance metadata. No external model was used. Astro-Han authorized this review campaign.

中文说明

此前 dev 版本识别和崩溃窗口 pairing recovery 两个 P2 均已修复:版本语法统一,Desktop 会在 profile mutation 前原子持久化恢复 journal,并在重启后完成幂等 finalize 或永久失败回滚。截图、十个 Codex trailer 和旧线程都已核实。当前只剩 inline 所述的 main compatibility epoch 冲突;请 rebase 后升 epoch、更新 fixture 并重跑 CI。

Comment thread packages/runtime-host/src/protocol/index.ts Outdated
@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch 2 times, most recently from 26ddf61 to ea3b69c Compare August 19, 2026 13:55
@M4n5ter
M4n5ter requested a review from Astro-Han August 19, 2026 15:18
M4n5ter added 14 commits August 21, 2026 09:51
Escalate cancelled or timed-out setup processes from graceful to forced termination and stop waiting after a bounded deadline. Reuse the same lifecycle for setup, development package upload, and terminal shutdown.

Generated-by: Codex
Keep one expiring pending credential per principal while preserving immediate replacement for standalone CLI setup. Commit only the pending candidate, make retries harmless, and align SSH cancellation with the completion boundary.

Generated-by: Codex
Reuse one per-principal staging path for development package uploads so a failed SSH handoff cannot accumulate orphaned archives. Successful setup still removes the staged package normally.

Generated-by: Codex
Replay idempotent credential finalization after uncertain commits or connection replacement, while restoring the prior profile after conclusive failures. Share one exact setup package validator so valid build metadata is accepted consistently.

Generated-by: Codex
Derive the Desktop setup package from the CLI release version so onboarding cannot target a stale command surface. Bound credential-authority shutdown and service replacement behavior, while keeping development archive setup portable and self-cleaning.

Generated-by: Codex
Run the prepare-stage CLI fixture against the version declared by the repository manifest so release validation remains stable across intentional CLI version bumps.

Generated-by: Codex
Terminate interactive SSH independently from onboarding settlement so shutdown cannot wait behind the process it must stop. Contain post-onboarding catalog refresh failures after the hook records the UI error state.

Generated-by: Codex
Align managed development releases with the generated package version grammar. Preserve published credential authority after uncertain commits, persist pending Desktop pairing transactions across process loss, and dismiss interactive SSH presentation when cancellation begins.

Generated-by: Codex
Serialize credential finalization with target shutdown so an in-flight commit can reconcile before its connection is retired. Make secret-file publication durable before dependent profile state is written, and remove the unused pairing intent UUID.

Generated-by: Codex
Advance the compatibility epoch for staged credential operations and let Desktop shutdown interrupt only pairing reconnect waits. Interrupted finalization retains its durable journal so the next startup can reconcile an unknown outcome without rolling back a potentially committed credential.

Generated-by: Codex
Keep setup metadata and pairing recovery scoped to onboarding so Desktop startup and existing remote Hosts remain available after recoverable failures. Model pairing as one durable intent, centralize profile activation, and preserve explicit repair and shutdown boundaries without duplicating defensive state.

Generated-by: Codex
Keep pairing recovery independent per profile so an offline Host does not block other onboarding. Bound credential finalization and release the interactive terminal once its tunnel is established.

Run remote npm setup from an isolated prefix, and require Desktop releases to select an exact CLI package that is already published.

Generated-by: Codex
Keep a completed SSH setup process under the terminal lifecycle until it actually exits, while releasing tunneled processes only after ownership transfers to the connection resource. This lets application shutdown terminate a remote setup that stalls after sending its completion frame.

Generated-by: Codex
Preserve the staged credential handoff while closing the demonstrated recovery and terminal-output gaps. Unify SSH destination validation, make finalization retries follow its idempotent contract, and let repeated Linux setup recover from systemd start limits.

Generated-by: Codex
@M4n5ter
M4n5ter force-pushed the feat/desktop-managed-remote-onboarding branch from 6cc6cd1 to 25bea91 Compare August 21, 2026 02:23
Refresh the generated surface count after the onboarding UI additions so the repository inventory check matches the current product surface.

Generated-by: Codex

@hqhq1025 hqhq1025 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local verification used Node 22.22.1 and npm 11.19.0. Build, typecheck, lint, format, release checks, the Runtime Host suite (1040 tests), and the CLI suite (337 tests) passed. The Desktop suite reproducibly ends with 997 passes and 9 cancellations because of the timeout finding below.

Codex-assisted review performed under the maintainer-approved review workflow.

Comment thread .github/workflows/release-desktop.yml Outdated
Comment thread apps/desktop/src/main/runtime-host-desktop-manager.ts Outdated
Comment thread packages/cli/src/runtime-host-systemd-service.ts
Keep the pairing deadline referenced on every supported Node version and clear a systemd unit start-limit state before restoring an active deployment.

Generated-by: Codex
@M4n5ter

M4n5ter commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

@hqhq1025 Thank you for the review. The confirmed findings are addressed in 8018923df:

  • Pairing finalization now keeps its deadline referenced until settlement. The complete manager test file passes on Node 22.22.1 with 19 tests and zero cancellations.
  • systemd rollback now clears the unit start-limit state before restarting an active previous deployment, with focused recovery-order coverage.

The release-package finding was adjudicated separately in its thread. We are retaining the protected manual release workflow as a trusted publisher boundary rather than adding a second compatibility mechanism or constraining the explicitly selected CLI version to the repository version.

All review threads have replies and are resolved. Please re-review the current head when convenient.

AI disclosure: OpenAI Codex posted this maintainer-directed summary after the fixes and validation were reviewed.

@hqhq1025 hqhq1025 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two prior code findings are fixed on this revision. Keeping the pairing-finalization deadline referenced eliminated the deterministic test cancellations (the complete Desktop suite passed 1006/1006 with zero cancellations), and active systemd rollback now resets the failed/start-limit state before restarting the prior unit (the service-manager suite passed 10/10).

[P1] .github/workflows/release-desktop.yml:66 still validates only that the exact input exists on npm, then embeds it into the released Desktop unchanged. The only published beta is maka-agent@0.1.0-beta.1; it passes this check but has no runtime-host setup command and uses compatibility epoch 24 while this Desktop uses 30. The live release environment only enforces the main-branch policy, and no release checklist step validates this package, so a normal release dispatch can produce an app whose Add computer flow deterministically fails. Require the selected package to match the repository CLI version, or give published packages a machine-readable setup/epoch probe and verify it before packaging.

Codex-assisted review performed under the maintainer-approved review workflow.

Derive the Runtime Host setup package from the CLI manifest and require that exact artifact to be public before packaging Desktop. This removes a redundant release input and prevents a valid but incompatible package from entering a release.

Generated-by: Codex
@M4n5ter

M4n5ter commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

@hqhq1025 Thank you for pressing on the release-package finding and for providing the concrete beta.1 counterexample.

We reconsidered the earlier trust-boundary decision. Trusting a release publisher is appropriate for decisions that require judgment, but this input only asked the publisher to repeat a value the repository already owns. We also found no current product requirement for pairing a Desktop release with a CLI version different from the CLI source in that release commit.

The revised design in 7127099bc therefore goes further than validating the manual input:

  • the manual runtime_host_setup_package input is removed;
  • the workflow derives maka-agent@<version> from packages/cli/package.json;
  • Desktop packaging proceeds only when that exact version is public on npm;
  • the derived specifier is the one embedded into the packaged application.

This leaves one version authority and no separate compatibility probe. At the current head, 0.1.0-beta.2 is not yet public, so Desktop release is intentionally blocked until the matching CLI release is complete.

The release workflow/publication policy tests, lint, and formatting checks pass. Please re-review the current head when convenient.

AI disclosure: OpenAI Codex posted this maintainer-directed explanation after the design decision and resulting change were reviewed.

@M4n5ter
M4n5ter requested a review from hqhq1025 August 21, 2026 05:50

@hqhq1025 hqhq1025 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved at exact head 7127099bcd2b1180e28af6e1094697712a075e0d.

No actionable code findings remain from my re-review. The previous release blocker is fixed at the correct authority: Release desktop now derives maka-agent@<packages/cli version>, requires that exact version to exist publicly, and only then exports it into electron-builder metadata. The repository currently names 0.1.0-beta.2, while the public registry contains only 0.1.0-beta.1, so the workflow fails closed today instead of embedding the known-incompatible package.

Problem definition and mechanism: the PR adds one guided SSH onboarding transaction spanning package deployment, staged Host credentials, verified local profile activation, credential finalization, and project selection. The Host-owned pending credential and Desktop pairing journal are not duplicate authorities: one bounds remote credential validity, while the other preserves the local profile/credential state needed to recover a crash between local persistence and remote finalization. After the recovery, timeout, cancellation, output-redaction, systemd rollback, and release-version fixes, the implementation follows those ownership boundaries consistently.

First principles and Occam's razor: the final structure is justified by the distributed commit boundary. Replacing an existing profile through a temporary new profile could reduce some rollback code, but it would change stable profile identity and still require durable recovery for crashes around Host finalization; I do not see evidence that it is a simpler equivalent solution. I found no production code that can be safely deleted without removing the development-package path or weakening recovery. The failure-path tests are behavioral and valuable; I found no low-quality test that should be removed. No deeper refactor is required for this revision.

Verification on this head:

  • npm run build:test, npm run typecheck, npm run lint, and npm run format:check passed.
  • npm run check:release passed after building the renderer artifact it checks.
  • CLI passed 337/337 tests.
  • The Runtime Host full suite passed 1038/1040 while run concurrently; both unrelated timeout failures passed when rerun serially.
  • Desktop passed 1004/1006 while run concurrently. The shell-output timeout passed serially; the unrelated Rive child-reaping test still times out on this machine. GitHub's main test check is green.

Merge verdict: the code is approved, but the revision is not ready to merge while the required Release Windows check is red. That job built and downloaded the update, then observed the old 0.1.11.0 process instead of the expected 0.1.12.<build> and could not remove the still-busy installation directory. The same verifier is currently failing on other branches with different launch/update symptoms, so I cannot attribute it to this PR from present evidence, but it must be rerun successfully before merge.

Residual verification gap: the PR's Windows check packages without MAKA_RUNTIME_HOST_SETUP_PACKAGE, so it does not exercise the exact setup-package metadata used by official releases. The release workflow itself is fail-closed and the development archive path was tested against a real Linux systemd user service, but the first release should still verify an actual packaged Add computer flow with the published 0.1.0-beta.2 CLI before publication.

@M4n5ter

M4n5ter commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

The remaining red Release Windows check is not attributable to this PR.

The Runtime Host onboarding review has converged and the current head is approved. The repository CI and dependency audit checks are green. The Windows job fails later in the existing automatic-update verifier: after installUpdate, it still observes the old 0.1.11.0 executable instead of the expected 0.1.12.<build>, then cleanup finds the installation directory busy.

That failure shape is already tracked as #3340: a surviving Runtime Host process can keep the installation directory in use, causing the NSIS handoff to leave the old version installed. The verifier-side instability and cleanup behavior are being addressed separately in #3327, which is approved and has a green end-to-end Windows lane at its current head.

#3348 also investigated product-side residue cleanup, but its current revision intentionally removed the unsafe untracked-PID termination path after review exposed a PID-reuse identity hazard. It therefore does not yet close the underlying #3340 lifecycle problem.

None of the failing verifier, updater, installer, or cleanup paths are changed by this PR. The failure should remain owned by the existing Windows update work rather than expanding this already-reviewed Remote Runtime Host onboarding change.

AI disclosure: OpenAI Codex posted this maintainer-directed status summary after checking the failing run and the related issue and PR heads.

@M4n5ter
M4n5ter merged commit 92da51d into main Aug 21, 2026
2 of 3 checks passed
@M4n5ter
M4n5ter deleted the feat/desktop-managed-remote-onboarding branch August 21, 2026 06:09
@hqhq1025

Copy link
Copy Markdown
Contributor

PR #3327 is now merged into main, so the Windows verifier fix is available. This PR still carries the earlier failed package run, but its source branch ref no longer exists (only refs/pull/3236/head remains), so GitHub cannot update the branch automatically. Please restore or refresh feat/desktop-managed-remote-onboarding onto current main so the required Windows package check can rerun. The code approval at 7127099bcd2b1180e28af6e1094697712a075e0d remains valid; the remaining gate is the refreshed package result.

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.

feat(desktop): add managed remote Runtime Host onboarding over SSH

3 participants