Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

[文档在这里](https://ccb.agent-aura.top/) | [留影文档在这里](./Friends.md) | [Discord 群组,群主在线答疑](https://discord.gg/uApuzJWGKX)

Windows 用户可安装[独立桌面窗口和一键启动快捷方式](scripts/windows-desktop/README.md)。

| 特性 | 说明 | 文档 |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **🎯 Goal 持续驱动** | `/goal <objective>` 设定目标后,自动跨轮驱动 agent 直至完成;带 token budget、completion/blocked audit、`pause`/`resume`/`continue`/`clear` 子命令,网络中断自动暂停 | 源码 [`commands/goal/`](./src/commands/goal/) · [`services/goal/`](./src/services/goal/) |
Expand Down
34 changes: 34 additions & 0 deletions docs/superpowers/plans/2026-11-09-windows-desktop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Windows Desktop Implementation Plan

> **For agentic workers:** Execute the following tasks inline in this session.

**Goal:** Publish a reusable Windows desktop shell and automatic shortcut installer.

**Architecture:** A WinForms/WebView2 shell loads the existing RCS UI. PowerShell restores the SDK, builds the executable, installs per-user files, and starts a loopback backend.

**Tech Stack:** C#, .NET Framework, WebView2, PowerShell, existing Bun backend.

**Spec:** User request: commit and submit automatic shortcut generation and desktop window support to claude-code-best/claude-code.

## Global Constraints

- Preserve workspace trust, sandbox and TLS checks.
- Exclude personal paths, providers, credentials, profiles, logs and binaries.
- Publish a focused branch against upstream main without unrelated fork history.

### Task 1: Portable client and installer

**Files:** `scripts/windows-desktop/{RealAgenticDesktop.cs,RealAgentic.png,build.ps1,start.ps1,install.ps1,.gitignore,README.md}`.

- [x] Move native window source and transparent logo into the source tree.
- [x] Restore pinned SDK into ignored sdk directory and compile into ignored build directory.
- [x] Generate per-user config and desktop shortcut with absolute install destinations.
- [x] Start existing local stack or upstream server/bridge; reuse healthy service.
- [x] Parse PowerShell scripts, compile C#, and run isolated install + WebView2 smoke test.
- [x] Inspect diff and commit only source, asset and documentation.

### Task 2: Upstream submission

- [x] Verify upstream permissions and create a fork when direct writing is unavailable.
- [ ] Push the focused branch and open a PR with validation and known limitations.
- [ ] Preserve preexisting local edits and report commit and PR URL.
11 changes: 11 additions & 0 deletions scripts/windows-desktop/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
build/
sdk/
*.ico
*.exe
*.dll
*.log
desktop-preview.png
desktop-verification*.json
desktop-config.json
transport-key.txt
WebView2Profile/
68 changes: 68 additions & 0 deletions scripts/windows-desktop/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Windows desktop client

A native x64 WinForms window embeds the RCS web UI using Microsoft Edge WebView2.
It has its own application identity and transparent icon, with no browser tabs or
address bar. External HTTP(S) links open in the default browser. Closing the window
leaves the service running; a second launch focuses the existing window.

## Install

Requires Windows 10/11 x64, .NET Framework 4.6.2 or later, PowerShell 5.1,
[WebView2 Evergreen Runtime](https://developer.microsoft.com/microsoft-edge/webview2/),
and Bun >= 1.3.0. Run from a source checkout:

```powershell
bun install
bun run --cwd packages/remote-control-server build:web
# Open the CLI once and explicitly accept trust for this checkout.
bun run dev
# Exit the CLI, then install:
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/windows-desktop/install.ps1
```

The installer downloads the pinned Microsoft.Web.WebView2 NuGet SDK 1.0.4314.35
from nuget.org, compiles with the Windows .NET Framework compiler, and installs to
`%LOCALAPPDATA%\RealAgenticDesktop`. It creates `RealAgentic.lnk` on the current
user's desktop. No administrator rights are required. The runtime itself must
already be installed; the SDK does not contain the Evergreen Runtime.

Double-click the shortcut to launch. On upstream, startup launches the loopback-only
RCS server and the `remote-control` bridge using a locally generated transport key.
On checkouts with `scripts/rcs-stack/main.ts`, it launches that local stack instead.
An already healthy server on port 3000 is reused; its existing worker configuration
is left to that server's owner. Health success confirms HTTP availability, not model
provider connectivity or worker readiness. Startup errors appear in the window;
server and worker output goes to the installation's `logs` directory.

Trust, provider authentication, and model configuration follow the normal CLI rules.
The installer never accepts trust automatically or changes sandbox settings.
Native Windows does not support the Linux/macOS Chat sandbox; use Code mode when
using a checkout that offers that distinction.

## Options

```powershell
# Supply a nonstandard Bun executable or choose another checkout:
.\scripts\windows-desktop\install.ps1 -BunPath 'C:\tools\bun.exe' -RepositoryPath 'D:\projects\claude-code'
# Embed an existing service without launching a backend:
.\scripts\windows-desktop\install.ps1 -ConnectOnly -Url 'https://rcs.example.com/code/'
# Build without installing or creating shortcuts:
.\scripts\windows-desktop\build.ps1
```

`-InstallDirectory` and `-ShortcutDirectory` allow custom destinations.
`-SkipBuild` reuses a previous build; `-NoShortcut` skips shortcut creation.
Close the desktop window before reinstalling. Re-run installation after moving
the checkout or Bun. Automatic startup currently uses port 3000; custom service
URLs require `-ConnectOnly`. No startup-at-login entry is created.

To uninstall, close the window and remove the shortcut and installation directory.
Stop any backend you started separately before removing its checkout. WebView2
cookies and local storage reside in `%LOCALAPPDATA%\RealAgenticDesktop\WebView2Profile`.
Local config, transport keys, logs, profiles, SDK files, and compiled binaries must
not be committed. The transparent PNG is a user-supplied, AI-edited logo asset;
the build generates an ICO with 16–256 pixel sizes from it.

For diagnostics, launch `RealAgentic.exe --verify`: it saves a window capture and
page/app-identity metadata beside the executable. Those files may contain private
session content and are excluded from version control.
Binary file added scripts/windows-desktop/RealAgentic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
212 changes: 212 additions & 0 deletions scripts/windows-desktop/RealAgenticDesktop.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;

[assembly: System.Reflection.AssemblyTitle("RealAgentic")]
[assembly: System.Reflection.AssemblyProduct("RealAgentic Desktop")]

internal static class Program
{
internal const string AppId = "RealAgentic.Desktop";
internal static string Home;
[DllImport("shell32.dll", CharSet = CharSet.Unicode)] private static extern int SetCurrentProcessExplicitAppUserModelID(string id);
[DllImport("shell32.dll")] private static extern int GetCurrentProcessExplicitAppUserModelID(out IntPtr id);
internal static string AppliedAppId { get; private set; }
[DllImport("user32.dll")] private static extern IntPtr FindWindow(string className, string title);
[DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr window);
[DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr window, int command);
[DllImport("user32.dll")] private static extern bool SetProcessDpiAwarenessContext(IntPtr context);

[STAThread]
private static void Main(string[] args)
{
try {
var json = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "desktop-config.json"));
var config = new JavaScriptSerializer().Deserialize<DesktopConfig>(json);
var url = new Uri(config.Url);
if (url.Scheme != "https" && !(url.Scheme == "http" && url.IsLoopback))
throw new InvalidOperationException("Use HTTPS or a local loopback URL.");
Home = url.AbsoluteUri;
} catch (Exception ex) {
MessageBox.Show(ex.Message, "RealAgentic configuration", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
try { SetProcessDpiAwarenessContext(new IntPtr(-4)); } catch { }
Marshal.ThrowExceptionForHR(SetCurrentProcessExplicitAppUserModelID(AppId));
IntPtr id;
Marshal.ThrowExceptionForHR(GetCurrentProcessExplicitAppUserModelID(out id));
try { AppliedAppId = Marshal.PtrToStringUni(id); } finally { Marshal.FreeCoTaskMem(id); }
using (var mutex = new Mutex(false, "Local\\RealAgenticDesktopWindow"))
{
bool acquired;
try { acquired = mutex.WaitOne(0); } catch (AbandonedMutexException) { acquired = true; }
if (!acquired)
{
var previous = FindWindow(null, "RealAgentic");
if (previous != IntPtr.Zero) { ShowWindow(previous, 9); SetForegroundWindow(previous); }
return;
}
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow(Array.IndexOf(args, "--verify") >= 0));
}
finally { mutex.ReleaseMutex(); }
}
}
}

internal sealed class MainWindow : Form
{
private readonly string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
private readonly bool verify;
private readonly Label status;
private readonly WebView2 view;
private readonly Panel loading;
private bool verificationStarted;
[DllImport("dwmapi.dll")] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attribute, ref int value, int size);

public MainWindow(bool verify)
{
this.verify = verify;
Text = "RealAgentic";
StartPosition = FormStartPosition.CenterScreen;
Size = new Size(1380, 900);
MinimumSize = new Size(950, 640);
WindowState = FormWindowState.Maximized;
BackColor = Color.FromArgb(25, 24, 23);
Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
loading = new Panel { Dock = DockStyle.Fill, BackColor = BackColor };
var layout = new TableLayoutPanel { Dock = DockStyle.Fill, ColumnCount = 1, RowCount = 5 };
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 45));
layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 100));
layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));
layout.RowStyles.Add(new RowStyle(SizeType.Absolute, 55));
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 55));
var logo = new PictureBox { Image = Image.FromFile(Path.Combine(appDirectory, "RealAgentic.png")), SizeMode = PictureBoxSizeMode.Zoom, Dock = DockStyle.Fill };
var title = new Label { Text = "RealAgentic", Dock = DockStyle.Fill, TextAlign = ContentAlignment.MiddleCenter, ForeColor = Color.White, Font = new Font("Segoe UI", 23, FontStyle.Bold) };
status = new Label { Text = "正在启动本地服务…", Dock = DockStyle.Fill, TextAlign = ContentAlignment.MiddleCenter, ForeColor = Color.Silver, Font = new Font("Microsoft YaHei UI", 11) };
layout.Controls.Add(logo, 0, 1);
layout.Controls.Add(title, 0, 2);
layout.Controls.Add(status, 0, 3);
loading.Controls.Add(layout);
view = new WebView2 { Dock = DockStyle.Fill, Visible = false, DefaultBackgroundColor = BackColor };
Controls.Add(view);
Controls.Add(loading);
Shown += async delegate { await InitializeAsync(); };
FormClosed += delegate { view.Dispose(); logo.Image.Dispose(); };
}

protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
try { int dark = 1; DwmSetWindowAttribute(Handle, 20, ref dark, sizeof(int)); } catch { }
}

private async Task InitializeAsync()
{
try
{
await StartBackendAsync();
if (IsDisposed) return;
status.Text = "正在打开工作区…";
var profile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "RealAgenticDesktop", "WebView2Profile");
var environment = await CoreWebView2Environment.CreateAsync(null, profile, null);
await view.EnsureCoreWebView2Async(environment);
if (IsDisposed) return;
view.CoreWebView2.Settings.IsStatusBarEnabled = false;
view.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = true;
view.CoreWebView2.NewWindowRequested += delegate(object sender, CoreWebView2NewWindowRequestedEventArgs e) {
e.Handled = true;
OpenExternal(e.Uri);
};
view.CoreWebView2.NavigationStarting += delegate(object sender, CoreWebView2NavigationStartingEventArgs e) {
Uri uri;
if (Uri.TryCreate(e.Uri, UriKind.Absolute, out uri) && (uri.Scheme == "http" || uri.Scheme == "https") && !IsLocal(uri))
{
e.Cancel = true;
OpenExternal(e.Uri);
}
};
view.CoreWebView2.NavigationCompleted += async delegate(object sender, CoreWebView2NavigationCompletedEventArgs e) {
if (!e.IsSuccess) { status.Text = "页面加载失败:" + e.WebErrorStatus; return; }
loading.Visible = false;
view.Visible = true;
view.BringToFront();
view.Focus();
if (verify && !verificationStarted)
{
verificationStarted = true;
await VerifyAsync();
}
};
view.CoreWebView2.Navigate(Program.Home);
}
catch (Exception ex)
{
if (IsDisposed) return;
status.Text = "启动失败,请查看提示。";
File.WriteAllText(Path.Combine(appDirectory, "desktop-error.log"), ex.ToString());
MessageBox.Show(this, ex.Message, "RealAgentic 启动失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

private async Task StartBackendAsync()
{
var script = Path.Combine(appDirectory, "start.ps1");
if (!File.Exists(script)) throw new FileNotFoundException("找不到服务启动脚本", script);
var executable = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
var info = new ProcessStartInfo(executable, "-NoProfile -ExecutionPolicy Bypass -File \"" + script + "\" -NoBrowser") {
UseShellExecute = false, CreateNoWindow = true, WorkingDirectory = appDirectory,
RedirectStandardOutput = true, RedirectStandardError = true
};
using (var process = Process.Start(info))
{
var output = process.StandardOutput.ReadToEndAsync();
var errors = process.StandardError.ReadToEndAsync();
var exited = Task.Run(() => process.WaitForExit());
if (await Task.WhenAny(exited, Task.Delay(115000)) != exited) throw new TimeoutException("服务启动超时,请检查 logs 文件夹。");
var stdout = await output;
var stderr = await errors;
if (process.ExitCode != 0) throw new InvalidOperationException("本地服务启动失败:\n" + stderr + "\n" + stdout);
}
}

private static bool IsLocal(Uri uri) { return uri.GetLeftPart(UriPartial.Authority) == new Uri(Program.Home).GetLeftPart(UriPartial.Authority); }
private static void OpenExternal(string target)
{
Uri uri;
if (Uri.TryCreate(target, UriKind.Absolute, out uri) && (uri.Scheme == "https" || uri.Scheme == "http"))
Process.Start(new ProcessStartInfo(uri.AbsoluteUri) { UseShellExecute = true });
}

private async Task VerifyAsync()
{
try
{
await Task.Delay(3000);
if (IsDisposed) return;
var result = await view.CoreWebView2.ExecuteScriptAsync("JSON.stringify({url:location.href,root:!!document.getElementById('root'),textLength:document.body.innerText.length})");
var serializer = new JavaScriptSerializer();
var page = serializer.Deserialize<string>(result);
using (var output = File.Create(Path.Combine(appDirectory, "desktop-preview.png")))
await view.CoreWebView2.CapturePreviewAsync(CoreWebView2CapturePreviewImageFormat.Png, output);
File.WriteAllText(Path.Combine(appDirectory, "desktop-verification.json"), serializer.Serialize(new { title = Text, nativeWindow = Handle.ToInt64(), appId = Program.AppliedAppId, browserAddressBar = false, page = serializer.DeserializeObject(page), screenshot = "desktop-preview.png" }));
}
catch (Exception ex) { File.WriteAllText(Path.Combine(appDirectory, "desktop-verification-error.log"), ex.ToString()); }
}
}

internal sealed class DesktopConfig
{
public string Url { get; set; }
}
Loading