feat: 启动进度提示、开机自启选项、应用内升级引导
- 启动等待时显示进度条+百分比+后端最新输出(等待上限 240s) - 托盘菜单新增"开机自启服务"勾选项(注册表 Run + vbs 隐藏启动器) - 启动后后台检查 DSH 最新版本,有新版弹窗引导升级(npm 后台完成,自动重启服务) - StartDshService 禁用 DSH_TELEMETRY_DISABLED 遥测(可能小幅加速) - 新增 start-dsh-service.vbs,更新 README
This commit is contained in:
1 parent
f8c101d487
commit
deba852624
4 files changed
+250
-18
No files matched your search
@@ -7,10 +7,14 @@
|
|||||||
|
|
||||||
- **独立窗口**:WebView2 渲染 `http://127.0.0.1:3080`,无浏览器地址栏/标签栏
|
- **独立窗口**:WebView2 渲染 `http://127.0.0.1:3080`,无浏览器地址栏/标签栏
|
||||||
- **自动拉起后端**:打开应用时若 dsh 服务未运行,自动静默启动(node 进程,无 CMD 窗口)
|
- **自动拉起后端**:打开应用时若 dsh 服务未运行,自动静默启动(node 进程,无 CMD 窗口)
|
||||||
|
- **启动进度提示**:等待后端就绪时显示进度条 + 百分比 + 后端最新输出(首次冷启动较慢)
|
||||||
- **系统托盘**:
|
- **系统托盘**:
|
||||||
- 点窗口 `X` → 直接最小化到托盘(后端保持运行)
|
- 点窗口 `X` → 直接最小化到托盘(后端保持运行)
|
||||||
- 托盘双击 / 右键「打开」→ 恢复窗口
|
- 托盘双击 / 右键「打开」→ 恢复窗口
|
||||||
- 托盘右键「退出」→ 完全退出(**同时关闭后端服务**)
|
- 右键「**开机自启服务**」→ 勾选后开机自动后台启动后端(打开应用秒开)
|
||||||
|
- 右键「退出」→ 完全退出(**同时关闭后端服务**)
|
||||||
|
- **应用内升级引导**:启动时后台检查 DSH 最新版本,有新版本弹窗引导升级
|
||||||
|
(npm 后台完成,无需打开浏览器/终端;升级后自动重启服务)
|
||||||
- **DPI 感知**:PerMonitorV2,高分屏(250% 缩放)下界面清晰不模糊
|
- **DPI 感知**:PerMonitorV2,高分屏(250% 缩放)下界面清晰不模糊
|
||||||
- **DeepSeek 官方图标**:窗口、任务栏、快捷方式均为官方鲸鱼 logo
|
- **DeepSeek 官方图标**:窗口、任务栏、快捷方式均为官方鲸鱼 logo
|
||||||
|
|
||||||
@@ -24,6 +28,7 @@ DeepSeekHarness\
|
|||||||
├── .gitignore 排除运行时数据
|
├── .gitignore 排除运行时数据
|
||||||
└── app\
|
└── app\
|
||||||
├── dsh-app.exe 主程序(C# / WinForms / WebView2)
|
├── dsh-app.exe 主程序(C# / WinForms / WebView2)
|
||||||
|
├── start-dsh-service.vbs 开机自启用的隐藏启动器(wscript 调用)
|
||||||
├── Microsoft.Web.WebView2.Core.dll WebView2 托管组件 1.0.3719.77
|
├── Microsoft.Web.WebView2.Core.dll WebView2 托管组件 1.0.3719.77
|
||||||
├── Microsoft.Web.WebView2.WinForms.dll 同上
|
├── Microsoft.Web.WebView2.WinForms.dll 同上
|
||||||
├── WebView2Loader.dll 原生加载器(x64)
|
├── WebView2Loader.dll 原生加载器(x64)
|
||||||
@@ -31,6 +36,7 @@ DeepSeekHarness\
|
|||||||
│ ├── dsh-app.cs 全部源码
|
│ ├── dsh-app.cs 全部源码
|
||||||
│ └── app.manifest DPI manifest(PerMonitorV2)
|
│ └── app.manifest DPI manifest(PerMonitorV2)
|
||||||
├── web.log dsh 服务日志(运行时生成)
|
├── web.log dsh 服务日志(运行时生成)
|
||||||
|
├── upgrade.log 升级日志(运行时生成)
|
||||||
└── dsh-app.exe.WebView2\ WebView2 用户数据(运行时生成)
|
└── dsh-app.exe.WebView2\ WebView2 用户数据(运行时生成)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -46,16 +52,16 @@ DeepSeekHarness\
|
|||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
1. 双击桌面(或 `C:\Users\VanuSystems-Mu\DeskBox\AI\`)的 **DeepSeek Harness** 快捷方式
|
1. 双击桌面(或 `C:\Users\VanuSystems-Mu\DeskBox\AI\`)的 **DeepSeek Harness** 快捷方式
|
||||||
2. 首次打开等待几秒(后端自动启动),之后秒开
|
2. 首次打开需等待后端冷启动(**2~3 分钟**,窗口有进度提示);之后秒开
|
||||||
3. 用完点 `X` 即最小化到托盘;想彻底退出用托盘右键 → **退出**
|
3. 用完点 `X` 即最小化到托盘;彻底退出用托盘右键 → **退出**
|
||||||
|
|
||||||
> 后端服务日志:`app\web.log`;启动失败排查:`app\start-error.log`(如存在)。
|
> **关于启动速度**:慢的根源是 dsh 自身(启动需加载 194 个插件包)。
|
||||||
|
> 推荐在托盘菜单勾选「**开机自启服务**」——开机后台预热,之后任何时间打开应用都是秒开。
|
||||||
|
|
||||||
## 从源码构建
|
## 从源码构建
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd app\src
|
cd app\src
|
||||||
# 需要 dsh.ico 与 app.manifest 位于 src 上级(或按需调整路径)
|
|
||||||
csc /target:winexe /nologo \
|
csc /target:winexe /nologo \
|
||||||
/win32manifest:app.manifest \
|
/win32manifest:app.manifest \
|
||||||
/win32icon:..\..\dsh.ico \
|
/win32icon:..\..\dsh.ico \
|
||||||
@@ -74,7 +80,8 @@ csc 位于 `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe`。
|
|||||||
|---|---|
|
|---|---|
|
||||||
| 界面模糊 | 确认 exe 已带 manifest(PerMonitorV2);重新构建 |
|
| 界面模糊 | 确认 exe 已带 manifest(PerMonitorV2);重新构建 |
|
||||||
| 弹 CMD 窗口 | 旧版本用 `cmd /c` 启动后端所致;当前版本直接启动 `node.exe`,无窗口 |
|
| 弹 CMD 窗口 | 旧版本用 `cmd /c` 启动后端所致;当前版本直接启动 `node.exe`,无窗口 |
|
||||||
| 打开后一直"正在启动服务" | 查看 `web.log`;确认 `dsh` 已全局安装、端口 3080 未被占用 |
|
| 打开后一直"正在启动服务" | dsh 冷启动需 2~3 分钟,进度条会显示;若超 4 分钟查看 `web.log` |
|
||||||
|
| 升级失败 | 查看 `app\upgrade.log`;确认 npm 镜像源可用 |
|
||||||
| 托盘图标消失 | 进程异常退出;重新双击快捷方式即可(会自动拉起后端) |
|
| 托盘图标消失 | 进程异常退出;重新双击快捷方式即可(会自动拉起后端) |
|
||||||
|
|
||||||
## 许可
|
## 许可
|
||||||
|
|||||||
Binary file not shown.
+233
-12
@@ -1,4 +1,4 @@
|
|||||||
// DeepSeek Harness — WebView2 独立桌面客户端(托盘常驻版)
|
// DeepSeek Harness — WebView2 独立桌面客户端
|
||||||
// 编译: csc /target:winexe /nologo /win32manifest:app.manifest /win32icon:dsh.ico
|
// 编译: csc /target:winexe /nologo /win32manifest:app.manifest /win32icon:dsh.ico
|
||||||
// /out:dsh-app.exe /r:Microsoft.Web.WebView2.Core.dll /r:Microsoft.Web.WebView2.WinForms.dll dsh-app.cs
|
// /out:dsh-app.exe /r:Microsoft.Web.WebView2.Core.dll /r:Microsoft.Web.WebView2.WinForms.dll dsh-app.cs
|
||||||
using System;
|
using System;
|
||||||
@@ -6,8 +6,10 @@ using System.Diagnostics;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using Microsoft.Win32;
|
||||||
using Microsoft.Web.WebView2.Core;
|
using Microsoft.Web.WebView2.Core;
|
||||||
using Microsoft.Web.WebView2.WinForms;
|
using Microsoft.Web.WebView2.WinForms;
|
||||||
|
|
||||||
@@ -15,11 +17,21 @@ static class Program
|
|||||||
{
|
{
|
||||||
private const int Port = 3080;
|
private const int Port = 3080;
|
||||||
private static readonly string WebUrl = "http://127.0.0.1:3080";
|
private static readonly string WebUrl = "http://127.0.0.1:3080";
|
||||||
|
private const int WaitSteps = 480; // 480 x 500ms = 240s 兜底
|
||||||
|
private const string RunKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||||
|
private const string RunValueName = "DeepSeekHarnessService";
|
||||||
|
|
||||||
|
private const string NodeExe = @"C:\Program Files\nodejs\node.exe";
|
||||||
|
private const string NpmCli = @"C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js";
|
||||||
|
|
||||||
private static Process serviceProcess; // 本应用拉起的 dsh 服务进程
|
private static Process serviceProcess; // 本应用拉起的 dsh 服务进程
|
||||||
private static bool startedByUs; // 服务是否由本应用启动
|
private static bool startedByUs; // 服务是否由本应用启动
|
||||||
private static NotifyIcon trayIcon;
|
private static NotifyIcon trayIcon;
|
||||||
private static Form mainForm;
|
private static Form mainForm;
|
||||||
|
private static WebView2 webView;
|
||||||
|
|
||||||
|
private static readonly object outputLock = new object();
|
||||||
|
private static string lastOutput; // 后端最新输出行(用于进度提示)
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
@@ -57,6 +69,14 @@ static class Program
|
|||||||
var menu = new ContextMenuStrip();
|
var menu = new ContextMenuStrip();
|
||||||
menu.Items.Add("打开 DeepSeek Harness", null, (s, e) => ShowMainWindow());
|
menu.Items.Add("打开 DeepSeek Harness", null, (s, e) => ShowMainWindow());
|
||||||
menu.Items.Add(new ToolStripSeparator());
|
menu.Items.Add(new ToolStripSeparator());
|
||||||
|
var autostart = new ToolStripMenuItem("开机自启服务")
|
||||||
|
{
|
||||||
|
CheckOnClick = true,
|
||||||
|
Checked = IsAutostartEnabled(),
|
||||||
|
};
|
||||||
|
autostart.Click += (s, e) => SetAutostart(autostart.Checked);
|
||||||
|
menu.Items.Add(autostart);
|
||||||
|
menu.Items.Add(new ToolStripSeparator());
|
||||||
menu.Items.Add("退出", null, (s, e) => ExitApp());
|
menu.Items.Add("退出", null, (s, e) => ExitApp());
|
||||||
trayIcon.ContextMenuStrip = menu;
|
trayIcon.ContextMenuStrip = menu;
|
||||||
|
|
||||||
@@ -68,6 +88,16 @@ static class Program
|
|||||||
mainForm.Hide();
|
mainForm.Hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 启动进度界面:阶段文字 + 进度条
|
||||||
|
var panel = new TableLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
RowCount = 2,
|
||||||
|
ColumnCount = 1,
|
||||||
|
};
|
||||||
|
panel.RowStyles.Add(new RowStyle(SizeType.Percent, 100));
|
||||||
|
panel.RowStyles.Add(new RowStyle(SizeType.Absolute, 36));
|
||||||
|
|
||||||
var status = new Label
|
var status = new Label
|
||||||
{
|
{
|
||||||
Dock = DockStyle.Fill,
|
Dock = DockStyle.Fill,
|
||||||
@@ -75,28 +105,51 @@ static class Program
|
|||||||
Font = new Font("Microsoft YaHei UI", 14),
|
Font = new Font("Microsoft YaHei UI", 14),
|
||||||
Text = "正在启动 DeepSeek Harness 服务…",
|
Text = "正在启动 DeepSeek Harness 服务…",
|
||||||
};
|
};
|
||||||
mainForm.Controls.Add(status);
|
var bar = new ProgressBar
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Fill,
|
||||||
|
Minimum = 0,
|
||||||
|
Maximum = WaitSteps,
|
||||||
|
Value = 0,
|
||||||
|
Style = ProgressBarStyle.Continuous,
|
||||||
|
Margin = new Padding(120, 4, 120, 16),
|
||||||
|
};
|
||||||
|
panel.Controls.Add(status, 0, 0);
|
||||||
|
panel.Controls.Add(bar, 0, 1);
|
||||||
|
mainForm.Controls.Add(panel);
|
||||||
|
|
||||||
var web = new WebView2 { Dock = DockStyle.Fill };
|
var web = new WebView2 { Dock = DockStyle.Fill };
|
||||||
|
|
||||||
mainForm.Shown += async (s, e) =>
|
mainForm.Shown += async (s, e) =>
|
||||||
{
|
{
|
||||||
// 等待服务就绪(最多 ~30 秒)
|
// 等待服务就绪(最多 ~240 秒,首次冷启动可能较慢),期间显示进度
|
||||||
bool ready = false;
|
bool ready = false;
|
||||||
for (int i = 0; i < 60; i++)
|
for (int i = 0; i < WaitSteps; i++)
|
||||||
{
|
{
|
||||||
await Task.Delay(500);
|
await Task.Delay(500);
|
||||||
|
int pct = Math.Min(99, i * 100 / WaitSteps);
|
||||||
|
string line;
|
||||||
|
lock (outputLock) { line = lastOutput; }
|
||||||
|
bar.Value = Math.Min(bar.Maximum, i);
|
||||||
|
status.Text = "正在启动 DeepSeek Harness 服务… " + pct + "%\n" +
|
||||||
|
(string.IsNullOrEmpty(line) ? "正在初始化后端…" : line);
|
||||||
if (IsPortOpen(Port)) { ready = true; break; }
|
if (IsPortOpen(Port)) { ready = true; break; }
|
||||||
}
|
}
|
||||||
if (!ready)
|
if (!ready)
|
||||||
{
|
{
|
||||||
|
bar.Value = bar.Maximum;
|
||||||
status.Text = "无法连接 DeepSeek Harness 服务(端口 " + Port + ")。\n" +
|
status.Text = "无法连接 DeepSeek Harness 服务(端口 " + Port + ")。\n" +
|
||||||
"请查看日志:" + Path.Combine(AppDir(), "web.log");
|
"请查看日志:" + Path.Combine(AppDir(), "web.log") + "\n" +
|
||||||
|
"或稍后从托盘重新打开窗口重试。";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bar.Value = bar.Maximum;
|
||||||
|
status.Text = "服务就绪,正在加载界面…";
|
||||||
|
await Task.Delay(300);
|
||||||
|
|
||||||
mainForm.SuspendLayout();
|
mainForm.SuspendLayout();
|
||||||
mainForm.Controls.Remove(status);
|
mainForm.Controls.Remove(panel);
|
||||||
mainForm.Controls.Add(web);
|
mainForm.Controls.Add(web);
|
||||||
mainForm.ResumeLayout();
|
mainForm.ResumeLayout();
|
||||||
|
|
||||||
@@ -109,6 +162,7 @@ static class Program
|
|||||||
cp.UserDataFolder = userData;
|
cp.UserDataFolder = userData;
|
||||||
web.CreationProperties = cp;
|
web.CreationProperties = cp;
|
||||||
await web.EnsureCoreWebView2Async();
|
await web.EnsureCoreWebView2Async();
|
||||||
|
webView = web;
|
||||||
web.Source = new Uri(WebUrl);
|
web.Source = new Uri(WebUrl);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -118,6 +172,9 @@ static class Program
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 后台检查 DSH 版本更新(有新版才提示,不阻塞启动)
|
||||||
|
CheckUpdateAsync();
|
||||||
|
|
||||||
Application.Run(mainForm);
|
Application.Run(mainForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,13 +203,12 @@ static class Program
|
|||||||
string logFile = Path.Combine(appDir, "web.log");
|
string logFile = Path.Combine(appDir, "web.log");
|
||||||
string npmDir = Path.Combine(
|
string npmDir = Path.Combine(
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "npm");
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "npm");
|
||||||
string nodeExe = @"C:\Program Files\nodejs\node.exe";
|
|
||||||
string binJs = Path.Combine(npmDir, "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js");
|
string binJs = Path.Combine(npmDir, "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!File.Exists(nodeExe) || !File.Exists(binJs)) return;
|
if (!File.Exists(NodeExe) || !File.Exists(binJs)) return;
|
||||||
|
|
||||||
var psi = new ProcessStartInfo(nodeExe)
|
var psi = new ProcessStartInfo(NodeExe)
|
||||||
{
|
{
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
@@ -170,17 +226,28 @@ static class Program
|
|||||||
path = npmDir + ";" + path;
|
path = npmDir + ";" + path;
|
||||||
psi.EnvironmentVariables["PATH"] = path;
|
psi.EnvironmentVariables["PATH"] = path;
|
||||||
|
|
||||||
|
// 禁用 dsh 启动遥测(可能小幅加速冷启动)
|
||||||
|
psi.EnvironmentVariables["DSH_TELEMETRY_DISABLED"] = "1";
|
||||||
|
|
||||||
serviceProcess = Process.Start(psi);
|
serviceProcess = Process.Start(psi);
|
||||||
startedByUs = true;
|
startedByUs = true;
|
||||||
|
|
||||||
// 输出写日志文件(防管道缓冲死锁)
|
// 输出写日志文件并记录最新行(供进度提示展示)
|
||||||
serviceProcess.OutputDataReceived += (s, e) =>
|
serviceProcess.OutputDataReceived += (s, e) =>
|
||||||
{
|
{
|
||||||
if (e.Data != null) { try { File.AppendAllText(logFile, e.Data + "\r\n"); } catch { } }
|
if (e.Data != null)
|
||||||
|
{
|
||||||
|
lock (outputLock) { lastOutput = e.Data; }
|
||||||
|
try { File.AppendAllText(logFile, e.Data + "\r\n"); } catch { }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
serviceProcess.ErrorDataReceived += (s, e) =>
|
serviceProcess.ErrorDataReceived += (s, e) =>
|
||||||
{
|
{
|
||||||
if (e.Data != null) { try { File.AppendAllText(logFile, e.Data + "\r\n"); } catch { } }
|
if (e.Data != null)
|
||||||
|
{
|
||||||
|
lock (outputLock) { lastOutput = e.Data; }
|
||||||
|
try { File.AppendAllText(logFile, e.Data + "\r\n"); } catch { }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
serviceProcess.BeginOutputReadLine();
|
serviceProcess.BeginOutputReadLine();
|
||||||
serviceProcess.BeginErrorReadLine();
|
serviceProcess.BeginErrorReadLine();
|
||||||
@@ -219,4 +286,158 @@ static class Program
|
|||||||
}
|
}
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- 开机自启 ----
|
||||||
|
|
||||||
|
static bool IsAutostartEnabled()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var key = Registry.CurrentUser.OpenSubKey(RunKeyPath))
|
||||||
|
{
|
||||||
|
return key != null && key.GetValue(RunValueName) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetAutostart(bool enable)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var key = Registry.CurrentUser.CreateSubKey(RunKeyPath))
|
||||||
|
{
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
string vbs = Path.Combine(AppDir(), "start-dsh-service.vbs");
|
||||||
|
key.SetValue(RunValueName, "wscript.exe \"" + vbs + "\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key.DeleteValue(RunValueName, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- DSH 版本检查与升级引导(应用内完成,无需浏览器/终端)----
|
||||||
|
|
||||||
|
static void CheckUpdateAsync()
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.Sleep(4000); // 等窗口稳定后再检查
|
||||||
|
string local = GetLocalVersion();
|
||||||
|
string latest = GetLatestVersion();
|
||||||
|
if (string.IsNullOrEmpty(latest) || latest == local) return;
|
||||||
|
string msg = "发现 DSH 新版本 " + latest + "(当前 " + local + ")。\n" +
|
||||||
|
"是否现在升级?升级在后台完成,无需打开浏览器或终端。";
|
||||||
|
mainForm.BeginInvoke((Action)(() =>
|
||||||
|
{
|
||||||
|
var r = MessageBox.Show(mainForm, msg, "DeepSeek Harness 更新",
|
||||||
|
MessageBoxButtons.YesNo, MessageBoxIcon.Information);
|
||||||
|
if (r != DialogResult.Yes) return;
|
||||||
|
bool ok = RunNpmUpgrade();
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
// 重启服务以加载新版本
|
||||||
|
try { if (serviceProcess != null && !serviceProcess.HasExited) serviceProcess.Kill(); } catch { }
|
||||||
|
Thread.Sleep(1500);
|
||||||
|
startedByUs = false;
|
||||||
|
StartDshService();
|
||||||
|
MessageBox.Show(mainForm,
|
||||||
|
"升级完成(" + local + " → " + latest + "),服务已重启。\n界面将自动刷新。",
|
||||||
|
"DeepSeek Harness", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
try { if (webView != null) webView.Reload(); } catch { }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show(mainForm,
|
||||||
|
"升级失败,请查看日志:" + Path.Combine(AppDir(), "upgrade.log"),
|
||||||
|
"DeepSeek Harness", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static string GetLocalVersion()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string pkg = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
|
"npm", "node_modules", "@deepseek-ai", "dsh", "package.json");
|
||||||
|
if (File.Exists(pkg))
|
||||||
|
{
|
||||||
|
var doc = new System.Text.RegularExpressions.Regex("\"version\"\\s*:\\s*\"([^\"]+)\"");
|
||||||
|
var m = doc.Match(File.ReadAllText(pkg));
|
||||||
|
if (m.Success) return m.Groups[1].Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static string GetLatestVersion()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string stdout = "";
|
||||||
|
var psi = new ProcessStartInfo(NodeExe)
|
||||||
|
{
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
Arguments = "\"" + NpmCli + "\" view @deepseek-ai/dsh version",
|
||||||
|
};
|
||||||
|
using (var p = Process.Start(psi))
|
||||||
|
{
|
||||||
|
p.ErrorDataReceived += (s, e) => { };
|
||||||
|
p.BeginErrorReadLine();
|
||||||
|
stdout = p.StandardOutput.ReadToEnd();
|
||||||
|
p.WaitForExit(60000);
|
||||||
|
}
|
||||||
|
return stdout.Trim();
|
||||||
|
}
|
||||||
|
catch { return ""; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool RunNpmUpgrade()
|
||||||
|
{
|
||||||
|
string logFile = Path.Combine(AppDir(), "upgrade.log");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var psi = new ProcessStartInfo(NodeExe)
|
||||||
|
{
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
WindowStyle = ProcessWindowStyle.Hidden,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
Arguments = "\"" + NpmCli + "\" install -g @deepseek-ai/dsh@latest",
|
||||||
|
};
|
||||||
|
using (var p = Process.Start(psi))
|
||||||
|
{
|
||||||
|
p.OutputDataReceived += (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.Data != null) { try { File.AppendAllText(logFile, e.Data + "\r\n"); } catch { } }
|
||||||
|
};
|
||||||
|
p.ErrorDataReceived += (s, e) =>
|
||||||
|
{
|
||||||
|
if (e.Data != null) { try { File.AppendAllText(logFile, e.Data + "\r\n"); } catch { } }
|
||||||
|
};
|
||||||
|
p.BeginOutputReadLine();
|
||||||
|
p.BeginErrorReadLine();
|
||||||
|
p.WaitForExit(180000);
|
||||||
|
return p.ExitCode == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { return false; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
' Start dsh (DeepSeek Harness) service in background, no window.
|
||||||
|
' Used by "autostart" tray option (registry Run entry via wscript).
|
||||||
|
Set ws = CreateObject("WScript.Shell")
|
||||||
|
ws.Run "cmd /c """"C:\Program Files\nodejs\node.exe"" ""C:\Users\VanuSystems-Mu\AppData\Roaming\npm\node_modules\@deepseek-ai\dsh\lib\bin.js"" web > ""C:\Users\VanuSystems-Mu\AppData\Local\DeepSeekHarness\app\web.log"" 2>&1""", 0, False
|
||||||
Reference in new issue
Block a user