feat: 支持离线运行时(runtime 目录)+ 动态生成自启 vbs
- FindNodeExe/FindDshBinJs/FindNpmCli:标准安装或应用旁 runtime 目录均可 - WriteServiceVbs 按当前环境动态生成(跨设备路径正确),启动时刷新 - 为离线安装包(Node 便携 + dsh 依赖内置)做准备
This commit is contained in:
1 parent
deba852624
commit
40a5640510
345 files changed
+353447
-24
No files matched your search
Binary file not shown.
+116
-22
@@ -21,8 +21,9 @@ static class Program
|
||||
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";
|
||||
// 标准安装路径(联网安装的 Node 默认位置);离线包使用应用旁的 runtime 目录
|
||||
private const string StdNodeExe = @"C:\Program Files\nodejs\node.exe";
|
||||
private const string StdNpmCli = @"C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js";
|
||||
|
||||
private static Process serviceProcess; // 本应用拉起的 dsh 服务进程
|
||||
private static bool startedByUs; // 服务是否由本应用启动
|
||||
@@ -175,6 +176,9 @@ static class Program
|
||||
// 后台检查 DSH 版本更新(有新版才提示,不阻塞启动)
|
||||
CheckUpdateAsync();
|
||||
|
||||
// 刷新开机自启启动器(路径随当前环境,跨设备可用)
|
||||
try { WriteServiceVbs(Path.Combine(AppDir(), "start-dsh-service.vbs")); } catch { }
|
||||
|
||||
Application.Run(mainForm);
|
||||
}
|
||||
|
||||
@@ -183,6 +187,62 @@ static class Program
|
||||
return Path.GetDirectoryName(Application.ExecutablePath);
|
||||
}
|
||||
|
||||
// 应用根目录(AppDir 的上一级,离线包布局 <root>/app、<root>/runtime)
|
||||
static string AppRoot()
|
||||
{
|
||||
string d = AppDir();
|
||||
return d != null ? Path.GetDirectoryName(d) : null;
|
||||
}
|
||||
|
||||
// ---- 运行时查找(标准安装 或 离线包 runtime 目录)----
|
||||
|
||||
static string FindNodeExe()
|
||||
{
|
||||
if (File.Exists(StdNodeExe)) return StdNodeExe;
|
||||
string root = AppRoot();
|
||||
if (root != null)
|
||||
{
|
||||
string local = Path.Combine(root, "runtime", "node", "node.exe");
|
||||
if (File.Exists(local)) return local;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static string GetNodeDir()
|
||||
{
|
||||
string exe = FindNodeExe();
|
||||
return exe != null ? Path.GetDirectoryName(exe) : null;
|
||||
}
|
||||
|
||||
static string FindNpmCli()
|
||||
{
|
||||
string nodeDir = GetNodeDir();
|
||||
if (nodeDir != null)
|
||||
{
|
||||
string cli = Path.Combine(nodeDir, "node_modules", "npm", "bin", "npm-cli.js");
|
||||
if (File.Exists(cli)) return cli;
|
||||
}
|
||||
if (File.Exists(StdNpmCli)) return StdNpmCli;
|
||||
return null;
|
||||
}
|
||||
|
||||
static string FindDshBinJs()
|
||||
{
|
||||
// 1) npm 全局(联网安装 / 离线复制到 APPDATA 的情况)
|
||||
string npmDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "npm");
|
||||
string p1 = Path.Combine(npmDir, "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js");
|
||||
if (File.Exists(p1)) return p1;
|
||||
// 2) 离线包布局 <root>/runtime/dsh/node_modules
|
||||
string root = AppRoot();
|
||||
if (root != null)
|
||||
{
|
||||
string p2 = Path.Combine(root, "runtime", "dsh", "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js");
|
||||
if (File.Exists(p2)) return p2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool IsPortOpen(int port)
|
||||
{
|
||||
try
|
||||
@@ -201,14 +261,18 @@ static class Program
|
||||
{
|
||||
string appDir = AppDir();
|
||||
string logFile = Path.Combine(appDir, "web.log");
|
||||
string npmDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "npm");
|
||||
string binJs = Path.Combine(npmDir, "node_modules", "@deepseek-ai", "dsh", "lib", "bin.js");
|
||||
string nodeExe = FindNodeExe();
|
||||
string binJs = FindDshBinJs();
|
||||
try
|
||||
{
|
||||
if (!File.Exists(NodeExe) || !File.Exists(binJs)) return;
|
||||
if (nodeExe == null || binJs == null)
|
||||
{
|
||||
try { File.WriteAllText(Path.Combine(AppDir(), "start-error.log"),
|
||||
"Node 或 dsh 未找到。nodeExe=" + (nodeExe ?? "null") + " binJs=" + (binJs ?? "null")); } catch { }
|
||||
return;
|
||||
}
|
||||
|
||||
var psi = new ProcessStartInfo(NodeExe)
|
||||
var psi = new ProcessStartInfo(nodeExe)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
@@ -220,10 +284,10 @@ static class Program
|
||||
|
||||
// 确保 node 与 npm 命令可用(dsh 插件可能用到)
|
||||
string path = psi.EnvironmentVariables["PATH"] ?? "";
|
||||
if (path.IndexOf("nodejs", StringComparison.OrdinalIgnoreCase) < 0)
|
||||
path = @"C:\Program Files\nodejs;" + path;
|
||||
if (path.IndexOf("npm", StringComparison.OrdinalIgnoreCase) < 0)
|
||||
path = npmDir + ";" + path;
|
||||
string nodeDir = Path.GetDirectoryName(nodeExe);
|
||||
if (nodeDir != null && path.IndexOf("nodejs", StringComparison.OrdinalIgnoreCase) < 0
|
||||
&& path.IndexOf(nodeDir, StringComparison.OrdinalIgnoreCase) < 0)
|
||||
path = nodeDir + ";" + path;
|
||||
psi.EnvironmentVariables["PATH"] = path;
|
||||
|
||||
// 禁用 dsh 启动遥测(可能小幅加速冷启动)
|
||||
@@ -310,6 +374,7 @@ static class Program
|
||||
if (enable)
|
||||
{
|
||||
string vbs = Path.Combine(AppDir(), "start-dsh-service.vbs");
|
||||
WriteServiceVbs(vbs);
|
||||
key.SetValue(RunValueName, "wscript.exe \"" + vbs + "\"");
|
||||
}
|
||||
else
|
||||
@@ -321,6 +386,25 @@ static class Program
|
||||
catch { }
|
||||
}
|
||||
|
||||
// 按当前环境动态生成隐藏启动器 vbs(路径随用户/安装位置变化)
|
||||
static void WriteServiceVbs(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
string nodeExe = FindNodeExe();
|
||||
string binJs = FindDshBinJs();
|
||||
if (nodeExe == null || binJs == null) return;
|
||||
string logFile = Path.Combine(AppDir(), "web.log");
|
||||
// cmd /c ""node" "bin.js" web > "log" 2>&1" (CreateProcess 剥一层引号后 cmd 仍收到带引号命令)
|
||||
string inner = "cmd /c \"\"" + nodeExe + "\" \"" + binJs + "\" web > \"" + logFile + "\" 2>&1\"";
|
||||
string vbs = "' Start dsh service (hidden, auto-generated)\r\n" +
|
||||
"Set ws = CreateObject(\"WScript.Shell\")\r\n" +
|
||||
"ws.Run \"" + inner.Replace("\"", "\"\"") + "\", 0, False\r\n";
|
||||
File.WriteAllText(path, vbs);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// ---- DSH 版本检查与升级引导(应用内完成,无需浏览器/终端)----
|
||||
|
||||
static void CheckUpdateAsync()
|
||||
@@ -369,14 +453,18 @@ static class Program
|
||||
{
|
||||
try
|
||||
{
|
||||
string pkg = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"npm", "node_modules", "@deepseek-ai", "dsh", "package.json");
|
||||
if (File.Exists(pkg))
|
||||
string binJs = FindDshBinJs();
|
||||
if (binJs != null)
|
||||
{
|
||||
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;
|
||||
string pkg = Path.Combine(
|
||||
Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(binJs))),
|
||||
"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 { }
|
||||
@@ -387,14 +475,17 @@ static class Program
|
||||
{
|
||||
try
|
||||
{
|
||||
string nodeExe = FindNodeExe();
|
||||
string cli = FindNpmCli();
|
||||
if (nodeExe == null || cli == null) return "";
|
||||
string stdout = "";
|
||||
var psi = new ProcessStartInfo(NodeExe)
|
||||
var psi = new ProcessStartInfo(nodeExe)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
Arguments = "\"" + NpmCli + "\" view @deepseek-ai/dsh version",
|
||||
Arguments = "\"" + cli + "\" view @deepseek-ai/dsh version",
|
||||
};
|
||||
using (var p = Process.Start(psi))
|
||||
{
|
||||
@@ -413,14 +504,17 @@ static class Program
|
||||
string logFile = Path.Combine(AppDir(), "upgrade.log");
|
||||
try
|
||||
{
|
||||
var psi = new ProcessStartInfo(NodeExe)
|
||||
string nodeExe = FindNodeExe();
|
||||
string cli = FindNpmCli();
|
||||
if (nodeExe == null || cli == null) return false;
|
||||
var psi = new ProcessStartInfo(nodeExe)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
Arguments = "\"" + NpmCli + "\" install -g @deepseek-ai/dsh@latest",
|
||||
Arguments = "\"" + cli + "\" install -g @deepseek-ai/dsh@latest",
|
||||
};
|
||||
using (var p = Process.Start(psi))
|
||||
{
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
' Start dsh (DeepSeek Harness) service in background, no window.
|
||||
' Used by "autostart" tray option (registry Run entry via wscript).
|
||||
' Start dsh service (hidden, auto-generated)
|
||||
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