Files

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";
}