@aipanel/provider-deepseek 1.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/api.d.ts +36 -0
- package/es/api.js +196 -0
- package/es/bridge-script.d.ts +11 -0
- package/es/bridge-script.js +142 -0
- package/es/constants.d.ts +25 -0
- package/es/constants.js +23 -0
- package/es/deepseek-web.d.ts +21 -0
- package/es/deepseek-web.js +62 -0
- package/es/dsh-install.d.ts +16 -0
- package/es/dsh-install.js +58 -0
- package/es/index.d.ts +16 -0
- package/es/index.js +29 -0
- package/es/profile.d.ts +11 -0
- package/es/profile.js +57 -0
- package/es/provider.d.ts +49 -0
- package/es/provider.js +290 -0
- package/es/system.d.ts +3 -0
- package/es/system.js +170 -0
- package/es/types.d.ts +127 -0
- package/es/types.js +19 -0
- package/lib/api.cjs +228 -0
- package/lib/api.d.ts +36 -0
- package/lib/bridge-script.cjs +165 -0
- package/lib/bridge-script.d.ts +11 -0
- package/lib/constants.cjs +52 -0
- package/lib/constants.d.ts +25 -0
- package/lib/deepseek-web.cjs +85 -0
- package/lib/deepseek-web.d.ts +21 -0
- package/lib/dsh-install.cjs +95 -0
- package/lib/dsh-install.d.ts +16 -0
- package/lib/index.cjs +63 -0
- package/lib/index.d.ts +16 -0
- package/lib/profile.cjs +91 -0
- package/lib/profile.d.ts +11 -0
- package/lib/provider.cjs +308 -0
- package/lib/provider.d.ts +49 -0
- package/lib/system.cjs +195 -0
- package/lib/system.d.ts +3 -0
- package/lib/types.cjs +42 -0
- package/lib/types.d.ts +127 -0
- package/package.json +34 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var dsh_install_exports = {};
|
|
29
|
+
__export(dsh_install_exports, {
|
|
30
|
+
DSH_CLIENT_PACKAGE: () => DSH_CLIENT_PACKAGE,
|
|
31
|
+
dshProfileDir: () => dshProfileDir,
|
|
32
|
+
ensureDshClient: () => ensureDshClient,
|
|
33
|
+
isDshClientInstalled: () => isDshClientInstalled,
|
|
34
|
+
resolveDevDshClientSource: () => resolveDevDshClientSource
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(dsh_install_exports);
|
|
37
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
38
|
+
var import_node_os = __toESM(require("node:os"));
|
|
39
|
+
var import_node_path = __toESM(require("node:path"));
|
|
40
|
+
var import_execa = require("execa");
|
|
41
|
+
var import_node_url = require("node:url");
|
|
42
|
+
var import_node = require("@aipanel/core/node");
|
|
43
|
+
const log = (0, import_node.createLogger)("DshInstall");
|
|
44
|
+
const DSH_CLIENT_PACKAGE = "@aipanel/dsh-client";
|
|
45
|
+
function resolveDevDshClientSource(metaUrl) {
|
|
46
|
+
const here = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(metaUrl));
|
|
47
|
+
const devDir = import_node_path.default.resolve(here, "../dsh-client");
|
|
48
|
+
if (import_node_fs.default.existsSync(import_node_path.default.join(devDir, "package.json")) && import_node_fs.default.existsSync(import_node_path.default.join(devDir, "lib/client.js"))) {
|
|
49
|
+
return devDir;
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function dshProfileDir(home) {
|
|
54
|
+
const resolved = home || process.env.DSH_HOME || import_node_path.default.join(import_node_os.default.homedir(), ".dsh");
|
|
55
|
+
return import_node_path.default.join(resolved, "profiles", "web");
|
|
56
|
+
}
|
|
57
|
+
function isDshClientInstalled(profileDir) {
|
|
58
|
+
return import_node_fs.default.existsSync(
|
|
59
|
+
import_node_path.default.join(profileDir, "node_modules", "@aipanel", "dsh-client", "package.json")
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
async function ensureDshClient(profileDir, target, home) {
|
|
63
|
+
try {
|
|
64
|
+
log.debug(`installing ${target} into dsh profile via dsh plugin add`);
|
|
65
|
+
await (0, import_execa.execa)("dsh", ["plugin", "--profile", "web", "add", target], {
|
|
66
|
+
reject: true,
|
|
67
|
+
shell: true,
|
|
68
|
+
env: {
|
|
69
|
+
...process.env,
|
|
70
|
+
...home ? { DSH_HOME: home } : {}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (!isDshClientInstalled(profileDir)) {
|
|
74
|
+
log.warn(`dsh plugin add finished but ${DSH_CLIENT_PACKAGE} is not resolvable`, {
|
|
75
|
+
profileDir
|
|
76
|
+
});
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
log.warn(`failed to install ${DSH_CLIENT_PACKAGE} via dsh plugin add`, {
|
|
82
|
+
target,
|
|
83
|
+
error: e instanceof Error ? e.message : String(e)
|
|
84
|
+
});
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
89
|
+
0 && (module.exports = {
|
|
90
|
+
DSH_CLIENT_PACKAGE,
|
|
91
|
+
dshProfileDir,
|
|
92
|
+
ensureDshClient,
|
|
93
|
+
isDshClientInstalled,
|
|
94
|
+
resolveDevDshClientSource
|
|
95
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const DSH_CLIENT_PACKAGE = "@aipanel/dsh-client";
|
|
2
|
+
/**
|
|
3
|
+
* 是否为 dev workspace 且 dsh-client 产物就绪(存在 package.json 与 lib/client.js)。
|
|
4
|
+
* 生产安装的 provider 在 node_modules/@aipanel/provider-deepseek/ 下,上一级不是 dsh-client,返回 null。
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveDevDshClientSource(metaUrl: string): string | null;
|
|
7
|
+
/** dsh web profile 目录(固定 --profile web);home 未指定时回退 $DSH_HOME / ~/.dsh */
|
|
8
|
+
export declare function dshProfileDir(home?: string): string;
|
|
9
|
+
/** @aipanel/dsh-client 在 profile 的 node_modules 中是否可解析 */
|
|
10
|
+
export declare function isDshClientInstalled(profileDir: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* 确保 @aipanel/dsh-client 已安装且为最新(官方命令 dsh plugin add)。
|
|
13
|
+
* 每次启动都执行(不跳过已安装):dev 本地目录每次重装保证改代码生效,
|
|
14
|
+
* 生产 npm 包每次检查 registry 拉取最新版本。安装失败返回 false(不阻塞启动,仅 chip 高亮不可用)。
|
|
15
|
+
*/
|
|
16
|
+
export declare function ensureDshClient(profileDir: string, target: string, home?: string): Promise<boolean>;
|
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var lib_exports = {};
|
|
19
|
+
__export(lib_exports, {
|
|
20
|
+
DEFAULT_DEEPSEEK_PROVIDER_OPTIONS: () => import_constants2.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
|
21
|
+
DSH_DEFAULT_PORT: () => import_constants2.DSH_DEFAULT_PORT,
|
|
22
|
+
DSH_LOOPBACK_HOST: () => import_constants2.DSH_LOOPBACK_HOST,
|
|
23
|
+
DeepSeekAPI: () => import_api.DeepSeekAPI,
|
|
24
|
+
buildDshOverlay: () => import_profile.buildDshOverlay,
|
|
25
|
+
checkDeepSeekInstalled: () => import_system.checkDeepSeekInstalled,
|
|
26
|
+
createProvider: () => createProvider,
|
|
27
|
+
generateBridgeScript: () => import_bridge_script.generateBridgeScript,
|
|
28
|
+
getDeepSeekVersion: () => import_system.getDeepSeekVersion,
|
|
29
|
+
killOrphanDeepSeekProcesses: () => import_system.killOrphanDeepSeekProcesses,
|
|
30
|
+
startDeepSeekWeb: () => import_deepseek_web.startDeepSeekWeb,
|
|
31
|
+
writeDshOverlay: () => import_profile.writeDshOverlay
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(lib_exports);
|
|
34
|
+
var import_provider = require("./provider.cjs");
|
|
35
|
+
var import_constants = require("./constants.cjs");
|
|
36
|
+
var import_api = require("./api.cjs");
|
|
37
|
+
var import_deepseek_web = require("./deepseek-web.cjs");
|
|
38
|
+
var import_profile = require("./profile.cjs");
|
|
39
|
+
var import_bridge_script = require("./bridge-script.cjs");
|
|
40
|
+
var import_system = require("./system.cjs");
|
|
41
|
+
var import_constants2 = require("./constants.cjs");
|
|
42
|
+
function createProvider(ctx) {
|
|
43
|
+
return new import_provider.DeepSeekWebProvider(
|
|
44
|
+
{ hostname: import_constants.DSH_LOOPBACK_HOST },
|
|
45
|
+
{ getWebPort: ctx.getWebPort, getProxyPort: ctx.getProxyPort },
|
|
46
|
+
ctx.options
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
|
52
|
+
DSH_DEFAULT_PORT,
|
|
53
|
+
DSH_LOOPBACK_HOST,
|
|
54
|
+
DeepSeekAPI,
|
|
55
|
+
buildDshOverlay,
|
|
56
|
+
checkDeepSeekInstalled,
|
|
57
|
+
createProvider,
|
|
58
|
+
generateBridgeScript,
|
|
59
|
+
getDeepSeekVersion,
|
|
60
|
+
killOrphanDeepSeekProcesses,
|
|
61
|
+
startDeepSeekWeb,
|
|
62
|
+
writeDshOverlay
|
|
63
|
+
});
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSeek Harness Web Provider
|
|
3
|
+
* 实现 WebProvider 契约:进程管理、RPC 会话 API、桥接脚本、CLI 环境检查。
|
|
4
|
+
* 所有 dsh 专属类型与常量自包含于此包。
|
|
5
|
+
*/
|
|
6
|
+
import type { ProviderInitContext, WebProvider } from "@aipanel/core";
|
|
7
|
+
/** 约定工厂:核心层动态加载本包后调用,初始化动作完全由 Provider 定义 */
|
|
8
|
+
export declare function createProvider(ctx: ProviderInitContext): WebProvider;
|
|
9
|
+
export { DeepSeekAPI } from "./api";
|
|
10
|
+
export type { DeepSeekWebProviderConfig, DeepSeekWebProviderDeps } from "./provider";
|
|
11
|
+
export { startDeepSeekWeb, type DeepSeekWebOptions } from "./deepseek-web";
|
|
12
|
+
export { buildDshOverlay, writeDshOverlay } from "./profile";
|
|
13
|
+
export { generateBridgeScript, type BridgeScriptOptions } from "./bridge-script";
|
|
14
|
+
export { checkDeepSeekInstalled, getDeepSeekVersion, killOrphanDeepSeekProcesses } from "./system";
|
|
15
|
+
export { DEFAULT_DEEPSEEK_PROVIDER_OPTIONS, DSH_LOOPBACK_HOST, DSH_DEFAULT_PORT } from "./constants";
|
|
16
|
+
export type { DeepSeekProviderOptions, DeepSeekPermissionPreset, DeepSeekBusyEnter, SessionSummary, WorkspaceView, SessionStreamEvent, ServerRequest, ServerResponse, ClientRequest, } from "./types";
|
package/lib/profile.cjs
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var profile_exports = {};
|
|
29
|
+
__export(profile_exports, {
|
|
30
|
+
buildDshOverlay: () => buildDshOverlay,
|
|
31
|
+
writeDshOverlay: () => writeDshOverlay
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(profile_exports);
|
|
34
|
+
var import_fs = __toESM(require("fs"));
|
|
35
|
+
var import_path = __toESM(require("path"));
|
|
36
|
+
var import_url = require("url");
|
|
37
|
+
var import_node = require("@aipanel/core/node");
|
|
38
|
+
const log = (0, import_node.createLogger)("DeepSeekProfile");
|
|
39
|
+
function buildDshOverlay(options) {
|
|
40
|
+
const { vitePort, cwd, pluginDistPath, clientAvailable = true } = options;
|
|
41
|
+
const mcpUrl = `http://127.0.0.1:${vitePort}${import_node.MCP_API_PATH}`;
|
|
42
|
+
const rows = [];
|
|
43
|
+
rows.push(
|
|
44
|
+
[
|
|
45
|
+
" - id: aipanel-mcp",
|
|
46
|
+
" name: '@deepseek-ai/dsh-mcp-client'",
|
|
47
|
+
" config:",
|
|
48
|
+
" serverName: aipanel",
|
|
49
|
+
" transport: streamable-http",
|
|
50
|
+
` url: ${mcpUrl}`,
|
|
51
|
+
" headers: {}"
|
|
52
|
+
].join("\n")
|
|
53
|
+
);
|
|
54
|
+
if (pluginDistPath && import_fs.default.existsSync(pluginDistPath)) {
|
|
55
|
+
const pluginSpec = (0, import_url.pathToFileURL)(pluginDistPath).href;
|
|
56
|
+
log.debug("injecting aipanel host plugin row", { pluginDistPath, pluginSpec });
|
|
57
|
+
rows.push(
|
|
58
|
+
[
|
|
59
|
+
" - id: aipanel",
|
|
60
|
+
` name: '${pluginSpec}'`,
|
|
61
|
+
" inject: [tools, subprocess]",
|
|
62
|
+
" config:",
|
|
63
|
+
` cwd: ${JSON.stringify(cwd)}`,
|
|
64
|
+
" autoDiagnose: true"
|
|
65
|
+
].join("\n")
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
log.debug("aipanel dsh-plugin dist not found, skipping host plugin row", { pluginDistPath });
|
|
69
|
+
}
|
|
70
|
+
rows.push(
|
|
71
|
+
[
|
|
72
|
+
" - id: aipanel-client",
|
|
73
|
+
" name: '@aipanel/dsh-client'",
|
|
74
|
+
...clientAvailable ? [] : [" disabled: true"]
|
|
75
|
+
].join("\n")
|
|
76
|
+
);
|
|
77
|
+
return ["- insert:", rows.join("\n"), ""].join("\n");
|
|
78
|
+
}
|
|
79
|
+
function writeDshOverlay(workspaceCwd, overlay) {
|
|
80
|
+
const dir = import_path.default.join(workspaceCwd, "node_modules", ".cache", "aipanel");
|
|
81
|
+
import_fs.default.mkdirSync(dir, { recursive: true });
|
|
82
|
+
const file = import_path.default.join(dir, "dsh-overlay.cordis.yml");
|
|
83
|
+
import_fs.default.writeFileSync(file, overlay, "utf-8");
|
|
84
|
+
log.debug("Wrote dsh overlay", { file });
|
|
85
|
+
return file;
|
|
86
|
+
}
|
|
87
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
88
|
+
0 && (module.exports = {
|
|
89
|
+
buildDshOverlay,
|
|
90
|
+
writeDshOverlay
|
|
91
|
+
});
|
package/lib/profile.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** 组装 overlay YAML */
|
|
2
|
+
export declare function buildDshOverlay(options: {
|
|
3
|
+
vitePort: number;
|
|
4
|
+
cwd: string;
|
|
5
|
+
pluginDistPath?: string;
|
|
6
|
+
/** client 插件是否可被 dsh 解析(provider 已同步到 dsh profile);false 时停用该行,避免 fail-loud */
|
|
7
|
+
clientAvailable?: boolean;
|
|
8
|
+
}): string;
|
|
9
|
+
/** 将 overlay 写入项目缓存目录(node_modules/.cache/aipanel,参照 opencode 的
|
|
10
|
+
* node_modules/.cache/opencode 惯例),不污染用户项目根目录。 */
|
|
11
|
+
export declare function writeDshOverlay(workspaceCwd: string, overlay: string): string;
|
package/lib/provider.cjs
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
20
|
+
var provider_exports = {};
|
|
21
|
+
__export(provider_exports, {
|
|
22
|
+
DeepSeekWebProvider: () => DeepSeekWebProvider
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(provider_exports);
|
|
25
|
+
const import_meta = {};
|
|
26
|
+
var import_node_url = require("node:url");
|
|
27
|
+
var import_node = require("@aipanel/core/node");
|
|
28
|
+
var import_constants = require("./constants.cjs");
|
|
29
|
+
var import_constants2 = require("./constants.cjs");
|
|
30
|
+
var import_api = require("./api.cjs");
|
|
31
|
+
var import_bridge_script = require("./bridge-script.cjs");
|
|
32
|
+
var import_deepseek_web = require("./deepseek-web.cjs");
|
|
33
|
+
var import_profile = require("./profile.cjs");
|
|
34
|
+
var import_system = require("./system.cjs");
|
|
35
|
+
var import_dsh_install = require("./dsh-install.cjs");
|
|
36
|
+
const log = (0, import_node.createLogger)("DeepSeekWebProvider");
|
|
37
|
+
class DeepSeekWebProvider {
|
|
38
|
+
constructor(config, deps, options) {
|
|
39
|
+
__publicField(this, "id", "deepseek");
|
|
40
|
+
__publicField(this, "displayName", "DeepSeek Harness");
|
|
41
|
+
/** SPA 型无 URL 深链:iframe 保持应用壳,切会话通过 FOCUS_SESSION 消息完成 */
|
|
42
|
+
__publicField(this, "capabilities", { deepLink: false });
|
|
43
|
+
__publicField(this, "api");
|
|
44
|
+
__publicField(this, "deps");
|
|
45
|
+
__publicField(this, "process", null);
|
|
46
|
+
__publicField(this, "bridgeOptions", {});
|
|
47
|
+
__publicField(this, "opts");
|
|
48
|
+
this.deps = deps;
|
|
49
|
+
this.opts = resolveDeepSeekOptions(options);
|
|
50
|
+
this.api = new import_api.DeepSeekAPI(import_constants2.DSH_LOOPBACK_HOST, deps.getWebPort);
|
|
51
|
+
}
|
|
52
|
+
/** 代理注入到 HTML 的桥接脚本(Provider 资产) */
|
|
53
|
+
get bridgeScript() {
|
|
54
|
+
return (0, import_bridge_script.generateBridgeScript)(this.bridgeOptions);
|
|
55
|
+
}
|
|
56
|
+
/** 初始化桥接配置(主题等) */
|
|
57
|
+
applyConfig(config) {
|
|
58
|
+
this.bridgeOptions = { theme: config.theme ?? "auto" };
|
|
59
|
+
}
|
|
60
|
+
async checkEnvironment() {
|
|
61
|
+
if (!await (0, import_system.checkDeepSeekInstalled)()) {
|
|
62
|
+
return {
|
|
63
|
+
ok: false,
|
|
64
|
+
message: `DeepSeek Harness (dsh) is not installed!
|
|
65
|
+
|
|
66
|
+
Please install dsh first:
|
|
67
|
+
|
|
68
|
+
npm install -g @deepseek-ai/dsh
|
|
69
|
+
|
|
70
|
+
or run without installing:
|
|
71
|
+
|
|
72
|
+
npx @deepseek-ai/dsh web
|
|
73
|
+
`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const version = await (0, import_system.getDeepSeekVersion)();
|
|
77
|
+
return { ok: true, version: version ?? void 0 };
|
|
78
|
+
}
|
|
79
|
+
async start(options) {
|
|
80
|
+
log.debug("Starting dsh web process", {
|
|
81
|
+
port: options.port,
|
|
82
|
+
hostname: import_constants2.DSH_LOOPBACK_HOST,
|
|
83
|
+
cwd: options.cwd,
|
|
84
|
+
vitePort: options.vitePort
|
|
85
|
+
});
|
|
86
|
+
const devClientDir = (0, import_dsh_install.resolveDevDshClientSource)(import_meta.url);
|
|
87
|
+
const clientAvailable = await (0, import_dsh_install.ensureDshClient)(
|
|
88
|
+
(0, import_dsh_install.dshProfileDir)(this.opts.home),
|
|
89
|
+
devClientDir ?? import_dsh_install.DSH_CLIENT_PACKAGE,
|
|
90
|
+
this.opts.home
|
|
91
|
+
);
|
|
92
|
+
if (!clientAvailable) {
|
|
93
|
+
log.warn("@aipanel/dsh-client unavailable; @ menu chip highlight disabled", {
|
|
94
|
+
metaUrl: import_meta.url
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const overlay = (0, import_profile.buildDshOverlay)({
|
|
98
|
+
vitePort: options.vitePort,
|
|
99
|
+
cwd: options.cwd,
|
|
100
|
+
pluginDistPath: this.resolvePluginDist(),
|
|
101
|
+
clientAvailable
|
|
102
|
+
});
|
|
103
|
+
const patchPath = (0, import_profile.writeDshOverlay)(options.cwd, overlay);
|
|
104
|
+
const proc = (0, import_deepseek_web.startDeepSeekWeb)({
|
|
105
|
+
port: options.port,
|
|
106
|
+
hostname: import_constants2.DSH_LOOPBACK_HOST,
|
|
107
|
+
cwd: options.cwd,
|
|
108
|
+
patchPath,
|
|
109
|
+
home: this.opts.home,
|
|
110
|
+
verbose: options.verbose
|
|
111
|
+
});
|
|
112
|
+
this.process = proc;
|
|
113
|
+
const settings = this.buildSettingsToApply();
|
|
114
|
+
if (Object.keys(settings).length > 0) {
|
|
115
|
+
void this.api.applySettings(settings).catch((e) => {
|
|
116
|
+
log.warn("failed to apply provider settings to dsh", {
|
|
117
|
+
settings,
|
|
118
|
+
error: e instanceof Error ? e.message : String(e)
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return { url: this.api.shellUrl, processHandle: proc };
|
|
123
|
+
}
|
|
124
|
+
/** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
|
|
125
|
+
buildSettingsToApply() {
|
|
126
|
+
const sections = {};
|
|
127
|
+
if (this.opts.agentPreset !== void 0) {
|
|
128
|
+
sections["agent-presets"] = { ...sections["agent-presets"], default: this.opts.agentPreset };
|
|
129
|
+
}
|
|
130
|
+
if (this.opts.permissionPreset !== void 0) {
|
|
131
|
+
sections.permission = {
|
|
132
|
+
...sections.permission,
|
|
133
|
+
defaultPreset: this.opts.permissionPreset
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (this.opts.busyEnter !== void 0) {
|
|
137
|
+
sections["ui-conversation"] = {
|
|
138
|
+
...sections["ui-conversation"],
|
|
139
|
+
busyEnter: this.opts.busyEnter
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return sections;
|
|
143
|
+
}
|
|
144
|
+
/** 解析 aipanel dsh-plugin 的构建产物路径(存在才在 overlay 里注入插件行)。
|
|
145
|
+
* 注意用 fileURLToPath:URL.pathname 是 percent-encoded,中文路径下 existsSync 会误判不存在。 */
|
|
146
|
+
resolvePluginDist() {
|
|
147
|
+
const fromHere = new URL("../dsh-plugin/dist/index.js", import_meta.url);
|
|
148
|
+
return (0, import_node_url.fileURLToPath)(fromHere);
|
|
149
|
+
}
|
|
150
|
+
async stop() {
|
|
151
|
+
if (this.process) {
|
|
152
|
+
log.debug("Killing dsh web process", { pid: this.process.pid });
|
|
153
|
+
this.process.kill("SIGTERM");
|
|
154
|
+
this.process = null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async killOrphans() {
|
|
158
|
+
return (0, import_system.killOrphanDeepSeekProcesses)();
|
|
159
|
+
}
|
|
160
|
+
async listSessions(projectDir) {
|
|
161
|
+
const sessions = await this.api.listSessions(projectDir);
|
|
162
|
+
const url = this.buildSessionUrl(projectDir, "");
|
|
163
|
+
return sessions.map((s) => toChatSession(s, url));
|
|
164
|
+
}
|
|
165
|
+
async createSession(projectDir, title) {
|
|
166
|
+
const url = this.buildSessionUrl(projectDir, "");
|
|
167
|
+
const created = await this.api.createSession(projectDir);
|
|
168
|
+
return {
|
|
169
|
+
id: created.sessionId,
|
|
170
|
+
title: title ?? "",
|
|
171
|
+
updatedAt: Date.now(),
|
|
172
|
+
url
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// 删除走归档:dsh 无硬删除语义(workspace.archiveSession),
|
|
176
|
+
// 归档后 listSessions 按 archivedSessionIds 过滤即从列表消失。
|
|
177
|
+
async deleteSession(sessionId) {
|
|
178
|
+
await this.api.archiveSession(sessionId);
|
|
179
|
+
}
|
|
180
|
+
buildSessionUrl(projectDir, sessionId) {
|
|
181
|
+
void projectDir;
|
|
182
|
+
void sessionId;
|
|
183
|
+
return `http://${import_constants2.DSH_LOOPBACK_HOST}:${this.deps.getProxyPort()}/`;
|
|
184
|
+
}
|
|
185
|
+
subscribeEvents(handler) {
|
|
186
|
+
const port = this.deps.getWebPort();
|
|
187
|
+
const base = `ws://${import_constants2.DSH_LOOPBACK_HOST}:${port}`;
|
|
188
|
+
const endpoints = [import_constants2.DSH_MUX_EVENTS_PATH, import_constants2.DSH_HOST_EVENTS_PATH];
|
|
189
|
+
log.debug("Subscribing to dsh event streams (WebSocket)", {
|
|
190
|
+
endpoints: endpoints.map((p) => base + p)
|
|
191
|
+
});
|
|
192
|
+
let aborted = false;
|
|
193
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
194
|
+
const retryTimers = /* @__PURE__ */ new Set();
|
|
195
|
+
const cleanupAll = () => {
|
|
196
|
+
for (const timer of retryTimers) clearTimeout(timer);
|
|
197
|
+
retryTimers.clear();
|
|
198
|
+
for (const ws of sockets) {
|
|
199
|
+
try {
|
|
200
|
+
ws.close();
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
sockets.clear();
|
|
205
|
+
};
|
|
206
|
+
const connect = (path, attempt = 0) => {
|
|
207
|
+
if (aborted) return;
|
|
208
|
+
let socket;
|
|
209
|
+
try {
|
|
210
|
+
socket = new WebSocket(base + path);
|
|
211
|
+
} catch (e) {
|
|
212
|
+
log.warn("dsh event WebSocket create failed", { path, error: String(e) });
|
|
213
|
+
scheduleReconnect(path, attempt + 1);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
sockets.add(socket);
|
|
217
|
+
socket.onmessage = (ev) => {
|
|
218
|
+
try {
|
|
219
|
+
const frame = JSON.parse(String(ev.data));
|
|
220
|
+
const event = mapEvent(frame);
|
|
221
|
+
if (event) handler(event);
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
socket.onclose = () => {
|
|
226
|
+
sockets.delete(socket);
|
|
227
|
+
scheduleReconnect(path, attempt + 1);
|
|
228
|
+
};
|
|
229
|
+
socket.onerror = () => {
|
|
230
|
+
try {
|
|
231
|
+
socket.close();
|
|
232
|
+
} catch {
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
};
|
|
236
|
+
const scheduleReconnect = (path, attempt) => {
|
|
237
|
+
if (aborted) return;
|
|
238
|
+
const delays = [250, 500, 1e3, 2e3, 5e3];
|
|
239
|
+
const after = delays[Math.min(attempt, delays.length - 1)];
|
|
240
|
+
const timer = setTimeout(() => {
|
|
241
|
+
retryTimers.delete(timer);
|
|
242
|
+
connect(path);
|
|
243
|
+
}, after);
|
|
244
|
+
retryTimers.add(timer);
|
|
245
|
+
};
|
|
246
|
+
endpoints.forEach((p) => connect(p));
|
|
247
|
+
return () => {
|
|
248
|
+
aborted = true;
|
|
249
|
+
cleanupAll();
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function mapEvent(frame) {
|
|
254
|
+
if (!frame || typeof frame.method !== "string" || !frame.payload) return null;
|
|
255
|
+
const payload = frame.payload;
|
|
256
|
+
const sessionId = payload.sessionId ?? "";
|
|
257
|
+
switch (frame.method) {
|
|
258
|
+
case "host/session-status": {
|
|
259
|
+
if (!sessionId) return null;
|
|
260
|
+
const running = payload.running === true;
|
|
261
|
+
return { type: "session.status", sessionId, status: running ? "running" : "idle" };
|
|
262
|
+
}
|
|
263
|
+
case "session/event": {
|
|
264
|
+
const event = payload.event;
|
|
265
|
+
const type = event?.type ?? "";
|
|
266
|
+
if (!sessionId || !type) return null;
|
|
267
|
+
switch (type) {
|
|
268
|
+
case "assistant/message":
|
|
269
|
+
case "turn/end":
|
|
270
|
+
return { type: "thinking", sessionId, thinking: false };
|
|
271
|
+
case "assistant/chunk":
|
|
272
|
+
case "thinking/delta":
|
|
273
|
+
case "turn/start":
|
|
274
|
+
case "step/start":
|
|
275
|
+
return { type: "thinking", sessionId, thinking: true };
|
|
276
|
+
default:
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
default:
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function toChatSession(s, url) {
|
|
285
|
+
return {
|
|
286
|
+
id: s.sessionId,
|
|
287
|
+
// dsh 标题在 projections.values.title,不在顶层
|
|
288
|
+
title: s.projections?.values?.title ?? "",
|
|
289
|
+
updatedAt: s.updatedAt,
|
|
290
|
+
parentId: s.parentSessionId,
|
|
291
|
+
url
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function resolveDeepSeekOptions(options) {
|
|
295
|
+
if (!options) return { ...import_constants.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS };
|
|
296
|
+
const po = options.providerOptions ?? {};
|
|
297
|
+
return {
|
|
298
|
+
...import_constants.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
|
299
|
+
home: po.home ?? options.home,
|
|
300
|
+
agentPreset: po.agentPreset ?? options.agentPreset,
|
|
301
|
+
permissionPreset: po.permissionPreset ?? options.permissionPreset,
|
|
302
|
+
busyEnter: po.busyEnter ?? options.busyEnter
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
306
|
+
0 && (module.exports = {
|
|
307
|
+
DeepSeekWebProvider
|
|
308
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ChatSession, ProviderConfig, ProviderEnvironmentInfo, ProviderEvent, ProviderStartOptions, ProviderStartResult, WebProvider } from "@aipanel/core";
|
|
2
|
+
/** DeepSeekWebProvider 构造配置(核心层传入的运行时参数) */
|
|
3
|
+
export interface DeepSeekWebProviderConfig {
|
|
4
|
+
/** 服务主机名 */
|
|
5
|
+
hostname: string;
|
|
6
|
+
}
|
|
7
|
+
/** DeepSeekWebProvider 构造依赖(端口等运行时状态由编排层提供) */
|
|
8
|
+
export interface DeepSeekWebProviderDeps {
|
|
9
|
+
/** 实际 Web 端口读取器 */
|
|
10
|
+
getWebPort: () => number;
|
|
11
|
+
/** 实际代理端口读取器 */
|
|
12
|
+
getProxyPort: () => number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* DeepSeek Harness Web Provider
|
|
16
|
+
* 组合 CLI 进程管理、RPC 会话 API、桥接脚本,向核心层暴露 WebProvider 契约。
|
|
17
|
+
*/
|
|
18
|
+
export declare class DeepSeekWebProvider implements WebProvider {
|
|
19
|
+
readonly id = "deepseek";
|
|
20
|
+
readonly displayName = "DeepSeek Harness";
|
|
21
|
+
/** SPA 型无 URL 深链:iframe 保持应用壳,切会话通过 FOCUS_SESSION 消息完成 */
|
|
22
|
+
readonly capabilities: {
|
|
23
|
+
readonly deepLink: false;
|
|
24
|
+
};
|
|
25
|
+
private readonly api;
|
|
26
|
+
private deps;
|
|
27
|
+
private process;
|
|
28
|
+
private bridgeOptions;
|
|
29
|
+
private readonly opts;
|
|
30
|
+
constructor(config: DeepSeekWebProviderConfig, deps: DeepSeekWebProviderDeps, options?: Record<string, unknown>);
|
|
31
|
+
/** 代理注入到 HTML 的桥接脚本(Provider 资产) */
|
|
32
|
+
get bridgeScript(): string | undefined;
|
|
33
|
+
/** 初始化桥接配置(主题等) */
|
|
34
|
+
applyConfig(config: ProviderConfig): void;
|
|
35
|
+
checkEnvironment(): Promise<ProviderEnvironmentInfo>;
|
|
36
|
+
start(options: ProviderStartOptions): Promise<ProviderStartResult>;
|
|
37
|
+
/** 把 providerOptions 配置映射为 dsh settings 命名空间 patch(仅含用户显式配置项) */
|
|
38
|
+
private buildSettingsToApply;
|
|
39
|
+
/** 解析 aipanel dsh-plugin 的构建产物路径(存在才在 overlay 里注入插件行)。
|
|
40
|
+
* 注意用 fileURLToPath:URL.pathname 是 percent-encoded,中文路径下 existsSync 会误判不存在。 */
|
|
41
|
+
private resolvePluginDist;
|
|
42
|
+
stop(): Promise<void>;
|
|
43
|
+
killOrphans(): Promise<number>;
|
|
44
|
+
listSessions(projectDir: string): Promise<ChatSession[]>;
|
|
45
|
+
createSession(projectDir: string, title?: string): Promise<ChatSession>;
|
|
46
|
+
deleteSession(sessionId: string): Promise<void>;
|
|
47
|
+
buildSessionUrl(projectDir: string, sessionId: string): string;
|
|
48
|
+
subscribeEvents(handler: (e: ProviderEvent) => void): () => void;
|
|
49
|
+
}
|