Skip to content
Open

Dev #22

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
afebd98
feat: add sync history tab, log viewer, QUIC auto-retry, and bug fixes
aceleisureman Jul 1, 2026
b847870
fix: prevent false cursor crossing at outer screen edge on macOS
aceleisureman Jul 1, 2026
ed81576
fix: add QUIC send retry with connection eviction
aceleisureman Jul 1, 2026
49da014
perf: offload sync history/log reads to blocking pool
aceleisureman Jul 1, 2026
59c8ee7
fix: prevent clipboard sync freeze with exponential backoff and QUIC …
aceleisureman Jul 1, 2026
0027a30
fix: auto-return cursor on QUIC datagram failure (prevent freeze on d…
aceleisureman Jul 1, 2026
3c5195a
fix: improve clipboard write retry with progressive backoff
aceleisureman Jul 1, 2026
d8f7425
perf: comprehensive optimization pass
aceleisureman Jul 1, 2026
593677d
Merge remote-tracking branch 'origin/main' into devin/sync-history-an…
aceleisureman Jul 13, 2026
fd7c1f6
docs: design bate preview updater channel
aceleisureman Jul 13, 2026
9fdb3c2
ci: publish bate previews from owned repository
aceleisureman Jul 13, 2026
1a3fef3
ci: build previews only from dev branch
aceleisureman Jul 13, 2026
06c15c1
build: configure owned updater signing key
aceleisureman Jul 13, 2026
5f2167f
ci: allow ad-hoc signed macOS preview builds
aceleisureman Jul 13, 2026
1959986
ci: skip DMG codesign check for beta previews
aceleisureman Jul 13, 2026
a903f52
docs: design balanced input and sync reliability
aceleisureman Jul 13, 2026
721b8af
docs: plan balanced input and sync reliability
aceleisureman Jul 13, 2026
96fd1b3
perf: isolate input from bulk sync traffic
aceleisureman Jul 13, 2026
905b14e
fix clipboard retries and reduce input diagnostics overhead
aceleisureman Jul 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Questions & Discussion
url: https://github.com/XxMinor/mykvm/discussions
url: https://github.com/aceleisureman/mykvm/discussions
about: Ask questions, share setups, and talk about ideas. Not sure if it's a bug? Start here.
- name: 📖 Documentation (README)
url: https://github.com/XxMinor/mykvm#readme
url: https://github.com/aceleisureman/mykvm#readme
about: Quick start, permissions, and limitations before filing an issue.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/setup_help.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
value: |
For general "how do I…" questions, the [Discussions board](https://github.com/XxMinor/mykvm/discussions) is often faster. Use this template when setup isn't working and you want help debugging.
For general "how do I…" questions, the [Discussions board](https://github.com/aceleisureman/mykvm/discussions) is often faster. Use this template when setup isn't working and you want help debugging.
- type: textarea
id: goal
attributes:
Expand Down
27 changes: 17 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ name: Release
on:
push:
branches:
- main
- bate
- dev
workflow_dispatch:
inputs:
channel:
Expand Down Expand Up @@ -66,7 +65,7 @@ jobs:
subject="$(git log -1 --pretty=%s)"
channel="${REQUESTED_CHANNEL:-}"
if [[ -z "$channel" ]]; then
if [[ "$REF_NAME" == "bate" ]]; then
if [[ "$REF_NAME" == "dev" ]]; then
channel="beta"
else
channel="stable"
Expand Down Expand Up @@ -322,8 +321,9 @@ jobs:
data.version = version;
if (file === 'src-tauri/tauri.conf.json' && channel === 'beta') {
data.plugins.updater.endpoints = [
'https://github.com/XxMinor/mykvm/releases/download/beta/latest.json',
'https://github.com/aceleisureman/mykvm/releases/download/beta/latest.json',
];
data.bundle.macOS.signingIdentity = '-';
}
fs.writeFileSync(file, `${JSON.stringify(data, null, 2)}\n`);
}
Expand All @@ -336,7 +336,7 @@ jobs:
NODE

- name: Validate Apple signing secrets
if: matrix.name == 'macos'
if: matrix.name == 'macos' && needs.prepare.outputs.channel != 'beta'
shell: bash
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
Expand Down Expand Up @@ -380,7 +380,7 @@ jobs:
exit "$missing"

- name: Configure Apple notarization
if: matrix.name == 'macos'
if: matrix.name == 'macos' && needs.prepare.outputs.channel != 'beta'
shell: bash
env:
APPLE_API_KEY_PRIVATE_KEY: ${{ secrets.APPLE_API_KEY_PRIVATE_KEY }}
Expand Down Expand Up @@ -424,7 +424,7 @@ jobs:
run: cargo check --manifest-path src-tauri/Cargo.toml

- name: Set up self-signed signing keychain
if: matrix.name == 'macos'
if: matrix.name == 'macos' && needs.prepare.outputs.channel != 'beta'
shell: bash
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
Expand Down Expand Up @@ -474,7 +474,6 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
# Notarization credentials are NOT wired in here: passing unset secrets
# injects empty strings, which Tauri reads as "present" and tries to
# notarize with blank creds. The "Configure Apple notarization" step
Expand Down Expand Up @@ -502,6 +501,7 @@ jobs:
if: matrix.name == 'macos'
shell: bash
env:
RELEASE_CHANNEL: ${{ needs.prepare.outputs.channel }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
run: |
Expand All @@ -528,12 +528,19 @@ jobs:

# The signature itself must always be valid.
codesign --verify --deep --strict --verbose=2 "$app_path"
codesign --verify --verbose=2 "$dmg_path"

# Preview DMGs wrap an ad-hoc signed app but are not themselves
# signed by Apple. Developer ID releases still require DMG signing.
if [ "$RELEASE_CHANNEL" != "beta" ]; then
codesign --verify --verbose=2 "$dmg_path"
else
echo "Ad-hoc signed beta: skipping DMG codesign verification."
fi

# spctl asserts Gatekeeper acceptance, which only holds for notarized
# builds. A free self-signed release is expected to fail it, so only
# run it when notarization credentials were provided.
if [ -n "${APPLE_API_KEY_ID:-}${APPLE_ID:-}" ]; then
if [ "$RELEASE_CHANNEL" != "beta" ] && [ -n "${APPLE_API_KEY_ID:-}${APPLE_ID:-}" ]; then
spctl -a -t exec -vv "$app_path"
spctl -a -t open --context context:primary-signature -vv "$dmg_path"
else
Expand Down
48 changes: 48 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@
"args": ["${workspaceFolder}/scripts/run-tauri-dev.sh"]
}
},
{
"label": "tauri:dev-build",
"type": "cargo",
"command": "build",
"args": [
"--manifest-path",
"${workspaceFolder}/src-tauri/Cargo.toml"
],
"problemMatcher": ["$rustc"],
"group": "build",
"presentation": {
"panel": "dedicated",
"reveal": "always",
"clear": true
}
},
{
"label": "check-dev-env",
"type": "shell",
Expand Down Expand Up @@ -77,6 +93,38 @@
"command": "npm.cmd",
"args": ["run", "tauri:build"]
}
},
{
"label": "cargo:check",
"type": "cargo",
"command": "check",
"args": [
"--manifest-path",
"${workspaceFolder}/src-tauri/Cargo.toml"
],
"problemMatcher": ["$rustc"],
"group": "build",
"presentation": {
"panel": "dedicated",
"reveal": "always",
"clear": true
}
},
{
"label": "cargo:test",
"type": "cargo",
"command": "test",
"args": [
"--manifest-path",
"${workspaceFolder}/src-tauri/Cargo.toml"
],
"problemMatcher": ["$rustc"],
"group": "test",
"presentation": {
"panel": "dedicated",
"reveal": "always",
"clear": true
}
}
]
}
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

Move your cursor off the edge of one screen and it lands on the next machine. Your keyboard follows, and the clipboard (text and images) syncs automatically. No KVM hardware, no cables.

[![Download](https://img.shields.io/github/v/release/XxMinor/mykvm?label=Download&style=for-the-badge)](https://github.com/XxMinor/mykvm/releases/latest)
[![Stars](https://img.shields.io/github/stars/XxMinor/mykvm?label=Stars&logo=github&style=for-the-badge)](https://github.com/XxMinor/mykvm/stargazers)
[![Forks](https://img.shields.io/github/forks/XxMinor/mykvm?label=Forks&logo=github&style=for-the-badge)](https://github.com/XxMinor/mykvm/forks)
[![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-2786ff?style=for-the-badge)](https://github.com/XxMinor/mykvm/releases/latest)
[![Download](https://img.shields.io/github/v/release/aceleisureman/mykvm?label=Download&style=for-the-badge)](https://github.com/aceleisureman/mykvm/releases/latest)
[![Stars](https://img.shields.io/github/stars/aceleisureman/mykvm?label=Stars&logo=github&style=for-the-badge)](https://github.com/aceleisureman/mykvm/stargazers)
[![Forks](https://img.shields.io/github/forks/aceleisureman/mykvm?label=Forks&logo=github&style=for-the-badge)](https://github.com/aceleisureman/mykvm/forks)
[![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20Windows%20%7C%20Linux-2786ff?style=for-the-badge)](https://github.com/aceleisureman/mykvm/releases/latest)
[![License: MIT](https://img.shields.io/badge/license-MIT-green?style=for-the-badge)](./LICENSE)

[中文说明](./README.zh-CN.md)
Expand All @@ -22,7 +22,7 @@ Move your cursor off the edge of one screen and it lands on the next machine. Yo

## Quick Start

1. **Install on both machines.** Download the installer for each OS from the [latest release](https://github.com/XxMinor/mykvm/releases/latest).
1. **Install on both machines.** Download the installer for each OS from the [latest release](https://github.com/aceleisureman/mykvm/releases/latest).
2. **Pick roles.** On the machine whose keyboard and mouse you want to share, open MyKVM and keep **Server** mode (the default). On the other machine, open MyKVM and switch to **Client** mode in Settings.
3. **Connect.** On the same LAN the two find each other automatically. Otherwise open **Devices**, type the other machine's IP (optionally `IP:port`), and click **Add**. Only devices that report their screen info join the layout.
4. **Arrange screens.** Open **Layout** and drag the monitors so their touching edges match how they sit on your desk.
Expand Down Expand Up @@ -60,7 +60,7 @@ Move your cursor off the edge of one screen and it lands on the next machine. Yo

## Current Status

MyKVM is an experimental early release. It is useful for local testing and iteration, but it is not hardened for untrusted networks. See the [Releases page](https://github.com/XxMinor/mykvm/releases) for the current version and installers.
MyKVM is an experimental early release. It is useful for local testing and iteration, but it is not hardened for untrusted networks. See the [Releases page](https://github.com/aceleisureman/mykvm/releases) for the current version and installers.

- License: MIT
- Default ports: UDP `47833` (discovery) and UDP `47834` (QUIC transport)
Expand Down
12 changes: 6 additions & 6 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

把光标移出一台屏幕的边缘,它就落到下一台机器上;键盘随之切换,剪贴板(文本和图片)自动同步。不需要 KVM 硬件,也不用插线。

[![下载](https://img.shields.io/github/v/release/XxMinor/mykvm?label=%E4%B8%8B%E8%BD%BD&style=for-the-badge)](https://github.com/XxMinor/mykvm/releases/latest)
[![Stars](https://img.shields.io/github/stars/XxMinor/mykvm?label=Stars&logo=github&style=for-the-badge)](https://github.com/XxMinor/mykvm/stargazers)
[![Forks](https://img.shields.io/github/forks/XxMinor/mykvm?label=Forks&logo=github&style=for-the-badge)](https://github.com/XxMinor/mykvm/forks)
[![平台](https://img.shields.io/badge/平台-macOS%20%7C%20Windows%20%7C%20Linux-2786ff?style=for-the-badge)](https://github.com/XxMinor/mykvm/releases/latest)
[![下载](https://img.shields.io/github/v/release/aceleisureman/mykvm?label=%E4%B8%8B%E8%BD%BD&style=for-the-badge)](https://github.com/aceleisureman/mykvm/releases/latest)
[![Stars](https://img.shields.io/github/stars/aceleisureman/mykvm?label=Stars&logo=github&style=for-the-badge)](https://github.com/aceleisureman/mykvm/stargazers)
[![Forks](https://img.shields.io/github/forks/aceleisureman/mykvm?label=Forks&logo=github&style=for-the-badge)](https://github.com/aceleisureman/mykvm/forks)
[![平台](https://img.shields.io/badge/平台-macOS%20%7C%20Windows%20%7C%20Linux-2786ff?style=for-the-badge)](https://github.com/aceleisureman/mykvm/releases/latest)
[![许可证: MIT](https://img.shields.io/badge/license-MIT-green?style=for-the-badge)](./LICENSE)

[English README](./README.md)
Expand All @@ -22,7 +22,7 @@

## 快速开始

1. **两台机器都安装。** 从 [最新发布](https://github.com/XxMinor/mykvm/releases/latest) 下载各自系统的安装包。
1. **两台机器都安装。** 从 [最新发布](https://github.com/aceleisureman/mykvm/releases/latest) 下载各自系统的安装包。
2. **选择角色。** 在要共享键鼠的那台机器上打开 MyKVM,保持 **服务端**(默认)。在另一台机器上打开 MyKVM,到设置里切换为 **客户端**。
3. **建立连接。** 同一局域网下两台会自动发现。否则打开 **设备**,输入对方 IP(可加 `IP:端口`),点 **添加**。只有上报了屏幕信息的设备才会加入布局。
4. **排列屏幕。** 打开 **布局**,拖动各显示器,让相邻边缘和它们在桌面上的实际位置一致。
Expand Down Expand Up @@ -60,7 +60,7 @@

## 当前状态

MyKVM 是一个实验性的早期版本,适合在本地可信网络中测试和迭代,但还没有面向不可信网络做生产级加固。当前版本和安装包见 [Releases 页面](https://github.com/XxMinor/mykvm/releases)。
MyKVM 是一个实验性的早期版本,适合在本地可信网络中测试和迭代,但还没有面向不可信网络做生产级加固。当前版本和安装包见 [Releases 页面](https://github.com/aceleisureman/mykvm/releases)。

- 许可证:MIT
- 默认端口:UDP `47833`(发现)和 UDP `47834`(QUIC 传输)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Balanced Input and Sync Reliability Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Prevent bulk sync work and one failed peer from degrading real-time input while making file retries safe.

**Architecture:** Keep the existing QUIC wire packets. Add peer-scoped datagram health, bound queued reliable streams, dispatch reliable sends without blocking the transport command loop, and accept already-written duplicate file chunks.

**Tech Stack:** Rust, Tokio, Quinn, Tauri

---

### Task 1: Isolate datagram health by peer

**Files:**
- Modify: `src-tauri/src/quic_transport.rs`

- [x] Add tests proving a failure recorded for peer A does not fast-fail peer B and success clears only the matching peer.
- [x] Run the focused QUIC tests and verify they fail before implementation.
- [x] Replace the global failure counter with a bounded peer-keyed health tracker.
- [x] Ensure enqueue failure rolls back pending counters.
- [x] Run focused QUIC tests and verify they pass.

### Task 2: Keep reliable streams from blocking input scheduling

**Files:**
- Modify: `src-tauri/src/quic_transport.rs`

- [x] Add tests for the reliable-stream pending budget.
- [x] Run the focused test and verify it fails before implementation.
- [x] Add a bounded stream pending counter.
- [x] Move stream send/retry work into spawned Tokio tasks using a shared connection registry.
- [x] Keep connection lookup locks outside stream ACK waits.
- [x] Run all QUIC transport tests.

### Task 3: Make file chunk retries idempotent

**Files:**
- Modify: `src-tauri/src/lib.rs`

- [x] Add a test that submits the same valid chunk twice and verifies the file contains one copy.
- [x] Run the focused test and verify it fails before implementation.
- [x] Accept a duplicate of the immediately previous fully-written chunk without writing it again.
- [x] Reject duplicates with mismatched offset or payload length.
- [x] Run the file-transfer tests and full Rust test suite.

### Task 4: Final verification

**Files:**
- Verify: Rust backend and frontend

- [x] Run `cargo fmt --manifest-path src-tauri/Cargo.toml -- --check`.
- [x] Run `cargo test --manifest-path src-tauri/Cargo.toml`.
- [x] Run `npm run lint`.
- [x] Run `npm run build`.
- [x] Run `git diff --check` and review the final diff.
- [x] Commit the implementation without `claude_auto_continue.py`.
40 changes: 40 additions & 0 deletions docs/superpowers/plans/2026-07-13-bate-preview-updater.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Dev Preview Updater Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Publish and update `dev` preview builds from `aceleisureman/mykvm` without operating on `main`.

**Architecture:** Keep the existing Tauri updater and GitHub Actions release pipeline. Trigger automatic releases only from `dev`, using the beta `beta/latest.json` channel in the user's repository.

**Tech Stack:** GitHub Actions, Tauri Updater v2, TypeScript, JSON

---

### Task 1: Point application links and updater endpoints to the owned repository

**Files:**
- Modify: `src/constants.ts`
- Modify: `src-tauri/tauri.conf.json`
- Modify: `src-tauri/src/lib.rs`

- [x] Replace `https://github.com/XxMinor/mykvm` with `https://github.com/aceleisureman/mykvm`.
- [x] Verify no runtime repository URL still references `XxMinor/mykvm` with `rg -n "XxMinor/mykvm" src src-tauri`.

### Task 2: Point beta build artifacts to the owned beta release channel

**Files:**
- Modify: `.github/workflows/release.yml`

- [x] Change the beta updater endpoint to `https://github.com/aceleisureman/mykvm/releases/download/beta/latest.json`.
- [x] Confirm the workflow triggers only for `dev` pushes.
- [x] Validate the YAML parses successfully.

### Task 3: Verify and commit

**Files:**
- Test: application and workflow configuration

- [x] Run `npm run build` and expect a successful Vite production build.
- [x] Run `cargo test --manifest-path src-tauri/Cargo.toml` and expect all tests to pass.
- [x] Run `git diff --check` and verify no whitespace errors.
- [ ] Commit the updater and release configuration changes.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Balanced Input and Sync Reliability Design

## Goal

Keep input latency low while preserving reliable clipboard and file transfer behavior under disconnects, congestion, and multiple peers.

## Architecture

The QUIC transport will schedule real-time datagrams independently from reliable streams. Datagram health and cooldown state will be tracked per peer so one unreachable device cannot poison another. Mouse movement may be coalesced or dropped under pressure, while keyboard, button, clipboard, and file data retain explicit success/failure semantics.

Reliable streams will use bounded priority classes. Clipboard/control traffic takes priority over bulk file chunks. File transfer receive handling will acknowledge safe duplicate chunks so an ACK loss does not abort an otherwise valid transfer.

## Behavior

- Input datagrams remain non-blocking and have a bounded pending budget.
- Each peer has independent consecutive-failure and cooldown state.
- Successful traffic clears only that peer's failure state.
- Stream sends run concurrently with datagram scheduling instead of blocking the transport command loop.
- Reliable stream concurrency is bounded to control memory and connection pressure.
- Duplicate file chunks already written at the expected previous index are accepted without writing twice.
- Queue pressure and peer failures remain visible through logs and focused unit tests.

## Compatibility

No wire protocol version change is required. Existing peers continue to decode the same packets. Duplicate-chunk acceptance only relaxes receiver behavior and remains compatible with older senders.

## Validation

- Unit tests cover peer-isolated health, bounded stream scheduling, and duplicate file chunks.
- Existing Rust tests must remain green.
- Frontend lint and production build must pass.
- No changes include the untracked `claude_auto_continue.py` file.
Loading