108 lines
3.7 KiB
JavaScript
108 lines
3.7 KiB
JavaScript
import path from "node:path";
|
|
import fs from "node:fs";
|
|
|
|
/** 当前已接线的宿主面。gui / tui 先能识别,适配仍回退 web。 */
|
|
export const SURFACES = Object.freeze(["web", "desktop", "gui", "tui"]);
|
|
|
|
function norm(value) {
|
|
return String(value || "").trim().toLowerCase();
|
|
}
|
|
|
|
function slash(value) {
|
|
return String(value || "").replace(/\\/g, "/").toLowerCase();
|
|
}
|
|
|
|
function exeName(execPath) {
|
|
return path.basename(String(execPath || "")).toLowerCase();
|
|
}
|
|
|
|
export function pathLooksDesktop(p) {
|
|
const n = slash(p);
|
|
if (!n) return false;
|
|
// 安装目录可能叫 "DeepSeek Harness" / "deepseek-harness" / "DeepseekHarnessDesktop"。
|
|
// 源码仓库也常带 deepseek-harness 名字,所以还要带 resources/、exe、.app/ 才算桌面安装。
|
|
const harnessDir =
|
|
n.includes("/deepseek harness/") ||
|
|
n.includes("/deepseek-harness/") ||
|
|
n.includes("/deepseekharness") ||
|
|
/\/deepseek[\s._-]*harness/.test(n);
|
|
return (
|
|
n.includes("/dsh desktop/") ||
|
|
n.includes("/dsh desktop.app/") ||
|
|
n.includes("dsh-desktop") ||
|
|
n.includes("dsh-plugin-desktop") ||
|
|
n.includes("/deepseek harness.app/") ||
|
|
(harnessDir && (n.includes("/resources/") || n.includes("/contents/resources/") || n.endsWith("/resources"))) ||
|
|
/\/dsh desktop\.exe$/i.test(n) ||
|
|
/\/deepseek[\s._-]*harness\.exe$/i.test(n) ||
|
|
n.endsWith("/host-process-entry.js") ||
|
|
n.endsWith("/desktop-cli.js")
|
|
);
|
|
}
|
|
|
|
function resourcesLookLikeDesktopInstall(resourcesPath) {
|
|
if (!resourcesPath) return false;
|
|
if (pathLooksDesktop(resourcesPath)) return true;
|
|
const n = slash(resourcesPath);
|
|
if (!(n.endsWith("/resources") || n.includes("/contents/resources"))) return false;
|
|
try {
|
|
const asar = path.join(resourcesPath, "app.asar");
|
|
if (fs.existsSync(asar) && fs.statSync(asar).isFile()) return true;
|
|
if (fs.existsSync(path.join(resourcesPath, "app", "dsh"))) return true;
|
|
if (fs.existsSync(path.join(resourcesPath, "app.asar.unpacked", "dsh"))) return true;
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
return false;
|
|
}
|
|
|
|
export function isDesktopSurface(input = {}) {
|
|
const env = input.env ?? process.env;
|
|
const forced = norm(env.DSH_SURFACE);
|
|
if (forced === "desktop") return true;
|
|
if (forced && SURFACES.includes(forced)) return false;
|
|
|
|
const execPath = input.execPath ?? process.execPath;
|
|
const name = exeName(execPath);
|
|
if (
|
|
name === "dsh desktop.exe" ||
|
|
name === "dsh desktop" ||
|
|
name === "deepseek harness.exe" ||
|
|
name === "deepseek-harness.exe" ||
|
|
name === "deepseek harness" ||
|
|
name === "deepseek-harness" ||
|
|
/^deepseek[\s._-]*harness(\.exe)?$/.test(name)
|
|
) return true;
|
|
if (pathLooksDesktop(execPath)) return true;
|
|
|
|
const resourcesPath = input.resourcesPath ?? process.resourcesPath;
|
|
if (resourcesLookLikeDesktopInstall(resourcesPath)) return true;
|
|
|
|
const argv = input.argv ?? process.argv;
|
|
if ((Array.isArray(argv) ? argv : []).some((arg) => pathLooksDesktop(arg))) return true;
|
|
|
|
const parentPort = input.parentPort !== undefined ? input.parentPort : process.parentPort;
|
|
if (parentPort && (pathLooksDesktop(execPath) || resourcesLookLikeDesktopInstall(resourcesPath))) return true;
|
|
|
|
if (env.ELECTRON_RUN_AS_NODE && (pathLooksDesktop(execPath) || resourcesLookLikeDesktopInstall(resourcesPath))) return true;
|
|
return false;
|
|
}
|
|
|
|
function forcedSurface(env) {
|
|
const forced = norm(env.DSH_SURFACE);
|
|
return SURFACES.includes(forced) ? forced : "";
|
|
}
|
|
|
|
export function detectSurface(input = {}) {
|
|
const env = input.env ?? process.env;
|
|
const forced = forcedSurface(env);
|
|
if (forced) return forced;
|
|
if (isDesktopSurface(input)) return "desktop";
|
|
return "web";
|
|
}
|
|
|
|
/** gui / tui 尚未单独适配,先走 web 重启与探测。 */
|
|
export function adapterFor(kind) {
|
|
return kind === "desktop" ? "desktop" : "web";
|
|
}
|