@aipanel/provider-deepseek 1.3.10 → 1.3.12
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/constants.js +2 -1
- package/es/deepseek-web.d.ts +12 -0
- package/es/deepseek-web.js +18 -2
- package/es/profile-check.d.ts +19 -0
- package/es/profile-check.js +41 -0
- package/es/provider.js +20 -1
- package/es/settings-layer.d.ts +24 -0
- package/es/settings-layer.js +47 -0
- package/es/types.d.ts +20 -2
- package/lib/constants.cjs +2 -1
- package/lib/deepseek-web.cjs +18 -2
- package/lib/deepseek-web.d.ts +12 -0
- package/lib/profile-check.cjs +77 -0
- package/lib/profile-check.d.ts +19 -0
- package/lib/provider.cjs +15 -0
- package/lib/settings-layer.cjs +84 -0
- package/lib/settings-layer.d.ts +24 -0
- package/lib/types.d.ts +20 -2
- package/package.json +2 -2
package/es/constants.js
CHANGED
|
@@ -4,7 +4,8 @@ const DSH_LOOPBACK_HOST = "127.0.0.1";
|
|
|
4
4
|
const DSH_DEFAULT_PORT = 3080;
|
|
5
5
|
const DSH_DEFAULT_PROFILE = "web";
|
|
6
6
|
const DEFAULT_DEEPSEEK_PROVIDER_OPTIONS = {
|
|
7
|
-
profile: DSH_DEFAULT_PROFILE
|
|
7
|
+
profile: DSH_DEFAULT_PROFILE,
|
|
8
|
+
settingsFrom: DSH_DEFAULT_PROFILE
|
|
8
9
|
};
|
|
9
10
|
export {
|
|
10
11
|
DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
package/es/deepseek-web.d.ts
CHANGED
|
@@ -33,6 +33,13 @@ export declare class LaunchToken {
|
|
|
33
33
|
fail(err: Error): void;
|
|
34
34
|
/** 窗口到点:输出 dsh web 启动原始日志辅助诊断,再按未捕获 token 判定本次启动失败 */
|
|
35
35
|
private expire;
|
|
36
|
+
/**
|
|
37
|
+
* 附上"这次起的是哪个 profile"的上下文(provider 起进程前调用)。
|
|
38
|
+
* 只加在这里、不进 printStartupOutput:超时的那条错误要能自己说清 profile 与它的 bundle 列表,
|
|
39
|
+
* 否则症状永远只是"启动超时"(见 profile-check 的注释)。
|
|
40
|
+
*/
|
|
41
|
+
attachContext(provider: () => string): void;
|
|
42
|
+
private context?;
|
|
36
43
|
/** 报错时把 dsh web 启动的原始日志作为一条日志整体输出(幂等:每实例只打一次) */
|
|
37
44
|
private printed;
|
|
38
45
|
private printStartupOutput;
|
|
@@ -52,6 +59,11 @@ export interface DeepSeekWebOptions {
|
|
|
52
59
|
profile?: string;
|
|
53
60
|
/** cordis overlay 文件路径(--patch 注入 MCP client / aipanel 插件) */
|
|
54
61
|
patchPath?: string;
|
|
62
|
+
/**
|
|
63
|
+
* 继承层路径(--patch 叠来源 profile 的配置,见 settings-layer.ts)。
|
|
64
|
+
* 必须排在 `patchPath` **之前**:`--patch` 越靠后越赢,AIPanel 自己插的插件行要压过来源 profile。
|
|
65
|
+
*/
|
|
66
|
+
settingsPatchPath?: string;
|
|
55
67
|
/** dsh 数据目录(透传 DSH_HOME;缺省跟随 $DSH_HOME / ~/.dsh) */
|
|
56
68
|
home?: string;
|
|
57
69
|
/** 启用 verbose 模式 */
|
package/es/deepseek-web.js
CHANGED
|
@@ -19,6 +19,7 @@ class LaunchToken {
|
|
|
19
19
|
/** dsh 进程是否已 spawn:token 只可能在 spawn 后打印,超时窗口自 arm 起算 */
|
|
20
20
|
__publicField(this, "spawned", false);
|
|
21
21
|
__publicField(this, "windowTimer");
|
|
22
|
+
__publicField(this, "context");
|
|
22
23
|
/** 报错时把 dsh web 启动的原始日志作为一条日志整体输出(幂等:每实例只打一次) */
|
|
23
24
|
__publicField(this, "printed", false);
|
|
24
25
|
}
|
|
@@ -63,12 +64,24 @@ class LaunchToken {
|
|
|
63
64
|
/** 窗口到点:输出 dsh web 启动原始日志辅助诊断,再按未捕获 token 判定本次启动失败 */
|
|
64
65
|
expire() {
|
|
65
66
|
this.printStartupOutput();
|
|
67
|
+
const context = this.context?.();
|
|
68
|
+
const base = `dsh launch token was not captured from stdout within ${this.timeoutMs}ms (dsh >= 0.1.2 should print the "dsh web: http://127.0.0.1:<port>/?token=..." URL)`;
|
|
66
69
|
this.fail(
|
|
67
70
|
new Error(
|
|
68
|
-
|
|
71
|
+
context === void 0 || context.trim() === "" ? base : `${base}
|
|
72
|
+
${context}
|
|
73
|
+
\uFF08\u8FD9\u4E2A profile \u8D77\u4E0D\u4E86 Web UI \u65F6\u5C31\u662F\u8FD9\u4E2A\u75C7\u72B6\uFF1A\u5148\u786E\u8BA4\u5B83\u5EFA\u597D\u4E86\uFF09`
|
|
69
74
|
)
|
|
70
75
|
);
|
|
71
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* 附上"这次起的是哪个 profile"的上下文(provider 起进程前调用)。
|
|
79
|
+
* 只加在这里、不进 printStartupOutput:超时的那条错误要能自己说清 profile 与它的 bundle 列表,
|
|
80
|
+
* 否则症状永远只是"启动超时"(见 profile-check 的注释)。
|
|
81
|
+
*/
|
|
82
|
+
attachContext(provider) {
|
|
83
|
+
this.context = provider;
|
|
84
|
+
}
|
|
72
85
|
printStartupOutput() {
|
|
73
86
|
if (this.printed) return;
|
|
74
87
|
this.printed = true;
|
|
@@ -93,9 +106,12 @@ class LaunchToken {
|
|
|
93
106
|
}
|
|
94
107
|
}
|
|
95
108
|
function startDeepSeekWeb(options) {
|
|
96
|
-
const { port, hostname, cwd, patchPath, home, verbose, launchToken } = options;
|
|
109
|
+
const { port, hostname, cwd, patchPath, settingsPatchPath, home, verbose, launchToken } = options;
|
|
97
110
|
const profile = options.profile ?? DSH_DEFAULT_PROFILE;
|
|
98
111
|
const args = ["--profile", profile];
|
|
112
|
+
if (settingsPatchPath) {
|
|
113
|
+
args.push("--patch", settingsPatchPath);
|
|
114
|
+
}
|
|
99
115
|
if (patchPath) {
|
|
100
116
|
args.push("--patch", patchPath);
|
|
101
117
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** dsh 的 Web 应用 bundle(`dsh web` 的 profile 必有;纯终端类 profile 没有) */
|
|
2
|
+
export declare const DSH_WEB_APP_BUNDLE = "@deepseek-ai/dsh-web-app";
|
|
3
|
+
export type DshProfileProblem = "missing" | "no-web-app";
|
|
4
|
+
export interface DshProfileInspection {
|
|
5
|
+
/** 这个 profile 现在能不能起 Web UI */
|
|
6
|
+
readonly ok: boolean;
|
|
7
|
+
/** 不能时是哪一类问题;能时为 null */
|
|
8
|
+
readonly problem: DshProfileProblem | null;
|
|
9
|
+
/** profile 声明的 bundle 列表(读不到时为空数组) */
|
|
10
|
+
readonly bundles: readonly string[];
|
|
11
|
+
/** profile 清单文件路径(报错信息里给绝对路径,方便直接去看) */
|
|
12
|
+
readonly manifest: string;
|
|
13
|
+
}
|
|
14
|
+
/** 读 profile 清单并判断它是否具备启动 Web UI 的条件 */
|
|
15
|
+
export declare function inspectDshProfile(profileDir: string): DshProfileInspection;
|
|
16
|
+
/** 预检没过时给用户的说明(通用措辞:说清是什么、去哪看、怎么修) */
|
|
17
|
+
export declare function profileProblemText(inspection: DshProfileInspection, profileDir: string, profile: string): string;
|
|
18
|
+
/** 启动超时诊断用的一行上下文:profile 在哪、声明了哪些 bundle */
|
|
19
|
+
export declare function describeDshProfile(profileDir: string, profile: string): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const DSH_WEB_APP_BUNDLE = "@deepseek-ai/dsh-web-app";
|
|
4
|
+
function inspectDshProfile(profileDir) {
|
|
5
|
+
const manifest = path.join(profileDir, "package.json");
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = JSON.parse(fs.readFileSync(manifest, "utf8"));
|
|
9
|
+
} catch {
|
|
10
|
+
return { ok: false, problem: "missing", bundles: [], manifest };
|
|
11
|
+
}
|
|
12
|
+
const declared = parsed?.dsh?.profile?.bundles;
|
|
13
|
+
const bundles = Array.isArray(declared) ? declared.filter((one) => typeof one === "string") : [];
|
|
14
|
+
if (!bundles.includes(DSH_WEB_APP_BUNDLE)) {
|
|
15
|
+
return { ok: false, problem: "no-web-app", bundles, manifest };
|
|
16
|
+
}
|
|
17
|
+
return { ok: true, problem: null, bundles, manifest };
|
|
18
|
+
}
|
|
19
|
+
function profileProblemText(inspection, profileDir, profile) {
|
|
20
|
+
const head = inspection.problem === "missing" ? `dsh profile "${profile}" \u8FD8\u4E0D\u5B58\u5728\uFF08\u627E\u4E0D\u5230 ${inspection.manifest}\uFF09` : `dsh profile "${profile}" \u91CC\u6CA1\u6709 Web \u5E94\u7528 bundle\uFF08${DSH_WEB_APP_BUNDLE}\uFF09`;
|
|
21
|
+
const bundles = inspection.bundles.length === 0 ? "\uFF08\u8BFB\u4E0D\u5230 bundle \u5217\u8868\uFF09" : `\u73B0\u6709 bundles\uFF1A${inspection.bundles.join("\u3001")}`;
|
|
22
|
+
return [
|
|
23
|
+
`${head}\uFF1A${profileDir}`,
|
|
24
|
+
` ${bundles}`,
|
|
25
|
+
" dsh \u5728 profile \u7F3A\u5931\u65F6\u4F1A\u81EA\u5DF1\u5EFA\u4E00\u4E2A\u53EA\u6709 @deepseek-ai/dsh-base \u7684\u7A7A\u58F3\uFF0C\u8D77\u6765\u4E0D\u4F1A\u6709\u754C\u9762\uFF1B",
|
|
26
|
+
" \u800C provider \u7684\u7F16\u6392\u662F\u300C\u5148\u88C5\u63D2\u4EF6\u3001\u518D\u8D77\u8FDB\u7A0B\u300D\uFF0C\u90A3\u4E00\u6B65\u4F1A\u628A\u7A7A\u58F3\u5EFA\u51FA\u6765\uFF0C\u75C7\u72B6\u53EA\u662F\u542F\u52A8\u8D85\u65F6\u3002",
|
|
27
|
+
" \u5148\u628A\u8FD9\u4E2A profile \u5EFA\u597D\uFF08\u5B83\u81EA\u5DF1\u7684\u5B89\u88C5\u6D41\u7A0B\uFF0C\u6216 `dsh <\u540D> --from-default-profile web`\uFF09\u518D\u91CD\u5F00\u3002"
|
|
28
|
+
].join("\n");
|
|
29
|
+
}
|
|
30
|
+
function describeDshProfile(profileDir, profile) {
|
|
31
|
+
const inspection = inspectDshProfile(profileDir);
|
|
32
|
+
const bundles = inspection.bundles.length === 0 ? "\uFF08\u8BFB\u4E0D\u5230\uFF09" : inspection.bundles.join("\u3001");
|
|
33
|
+
return `profile: ${profile} (${profileDir})
|
|
34
|
+
bundles: ${bundles}`;
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
DSH_WEB_APP_BUNDLE,
|
|
38
|
+
describeDshProfile,
|
|
39
|
+
inspectDshProfile,
|
|
40
|
+
profileProblemText
|
|
41
|
+
};
|
package/es/provider.js
CHANGED
|
@@ -4,10 +4,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4
4
|
import { sleep } from "@aipanel/core";
|
|
5
5
|
import { DEFAULT_DIAGNOSTICS_POLICY, resolveDiagnosticsPolicy } from "@aipanel/core";
|
|
6
6
|
import { createLogger } from "@aipanel/core/node";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
|
9
|
+
DSH_DEFAULT_PROFILE,
|
|
10
|
+
DSH_LOOPBACK_HOST
|
|
11
|
+
} from "./constants.js";
|
|
8
12
|
import { DeepSeekAPI } from "./api.js";
|
|
9
13
|
import { LaunchToken, startDeepSeekWeb } from "./deepseek-web.js";
|
|
10
14
|
import { buildDshOverlay, writeDshOverlay } from "./profile.js";
|
|
15
|
+
import { describeDshProfile, inspectDshProfile, profileProblemText } from "./profile-check.js";
|
|
16
|
+
import { inheritSourceOf, writeInheritLayer } from "./settings-layer.js";
|
|
11
17
|
import {
|
|
12
18
|
checkDeepSeekInstalled,
|
|
13
19
|
getDeepSeekVersion,
|
|
@@ -91,6 +97,14 @@ Please upgrade:
|
|
|
91
97
|
const launchToken = new LaunchToken();
|
|
92
98
|
this.launchToken = launchToken;
|
|
93
99
|
this.api.setLaunchTokenSource(() => launchToken.wait());
|
|
100
|
+
launchToken.attachContext(() => describeDshProfile(profileDir, this.opts.profile));
|
|
101
|
+
const profileCheck = inspectDshProfile(profileDir);
|
|
102
|
+
if (!profileCheck.ok) {
|
|
103
|
+
const reason = profileProblemText(profileCheck, profileDir, this.opts.profile);
|
|
104
|
+
log.error(reason);
|
|
105
|
+
launchToken.fail(new Error(reason));
|
|
106
|
+
throw new Error(reason);
|
|
107
|
+
}
|
|
94
108
|
const devClientDir = resolveDevDshPackageSource(import.meta.url, "dsh-client", "lib/client.js");
|
|
95
109
|
const providerVersion = readProviderVersion(import.meta.url);
|
|
96
110
|
const clientTarget = devClientDir ?? (providerVersion ? `${DSH_CLIENT_PACKAGE}@${providerVersion}` : `${DSH_CLIENT_PACKAGE}@latest`);
|
|
@@ -137,12 +151,15 @@ Please upgrade:
|
|
|
137
151
|
theme: this.uiTheme
|
|
138
152
|
});
|
|
139
153
|
const patchPath = writeDshOverlay(options.cwd, overlay);
|
|
154
|
+
const inheritSource = inheritSourceOf(this.opts.profile, this.opts.settingsFrom);
|
|
155
|
+
const settingsPatchPath = inheritSource === null ? null : writeInheritLayer({ cwd: options.cwd, home: this.opts.home, source: inheritSource });
|
|
140
156
|
const proc = startDeepSeekWeb({
|
|
141
157
|
port: options.port,
|
|
142
158
|
hostname: DSH_LOOPBACK_HOST,
|
|
143
159
|
cwd: options.cwd,
|
|
144
160
|
profile: this.opts.profile,
|
|
145
161
|
patchPath,
|
|
162
|
+
...settingsPatchPath === null ? {} : { settingsPatchPath },
|
|
146
163
|
home: this.opts.home,
|
|
147
164
|
verbose: options.verbose,
|
|
148
165
|
launchToken
|
|
@@ -237,6 +254,8 @@ function resolveDeepSeekOptions(options) {
|
|
|
237
254
|
...DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
|
238
255
|
home: po.home ?? options?.home,
|
|
239
256
|
profile: po.profile ?? options?.profile ?? DSH_DEFAULT_PROFILE,
|
|
257
|
+
// 默认就叠(见 settings-layer.ts):用户不会去改配置,机器级设置只配一次是默认预期。
|
|
258
|
+
settingsFrom: po.settingsFrom === false ? false : typeof po.settingsFrom === "string" ? po.settingsFrom : DSH_DEFAULT_PROFILE,
|
|
240
259
|
agentPreset: po.agentPreset ?? options?.agentPreset,
|
|
241
260
|
permissionPreset: po.permissionPreset ?? options?.permissionPreset,
|
|
242
261
|
busyEnter: po.busyEnter ?? options?.busyEnter,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** 不跟着来源走的那几行(每个界面自己的偏好);理由见文件头 */
|
|
2
|
+
export declare const INHERIT_SKIP_IDS: readonly string[];
|
|
3
|
+
/** 生成层落在项目缓存目录,与 AIPanel 自己的 overlay 同处 */
|
|
4
|
+
export declare const INHERIT_LAYER_FILENAME = "dsh-inherit.cordis.yml";
|
|
5
|
+
/**
|
|
6
|
+
* 该从哪个 profile 继承。
|
|
7
|
+
* @param settingsFrom 解析后的选项:profile 名 / `false`(不叠)
|
|
8
|
+
* @returns 源 profile 名;`null` = 不叠(关掉了,或目标就是它自己)
|
|
9
|
+
*/
|
|
10
|
+
export declare function inheritSourceOf(profile: string, settingsFrom: string | false): string | null;
|
|
11
|
+
/**
|
|
12
|
+
* 按**顶层条目**剥掉若干 `- id:` 块(与 dsh-workbench 启动器里那段 awk 同口径:从命中的 `- ` 行
|
|
13
|
+
* 一路丢到下一个顶层 `- ` 为止)。手写而不是上 YAML 库:这一层只是转交一份文本,没必要为它引入依赖,
|
|
14
|
+
* 也不能因为来源文件里有 `!!js` 之类的 dsh 扩展标签就解析失败。
|
|
15
|
+
*/
|
|
16
|
+
export declare function stripEntries(text: string, skipIds: readonly string[]): string;
|
|
17
|
+
/**
|
|
18
|
+
* 写出继承层并返回它的路径;来源不存在/读不动时返回 `null`(**不阻断启动**:少了它只是回到老行为)。
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeInheritLayer(input: {
|
|
21
|
+
cwd: string;
|
|
22
|
+
home?: string | undefined;
|
|
23
|
+
source: string;
|
|
24
|
+
}): string | null;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { AIPANEL_CACHE_DIR, createLogger } from "@aipanel/core/node";
|
|
4
|
+
import { dshProfileDir } from "./dsh-install.js";
|
|
5
|
+
const log = createLogger("DeepSeekSettings");
|
|
6
|
+
const INHERIT_SKIP_IDS = ["ui-theme"];
|
|
7
|
+
const INHERIT_LAYER_FILENAME = "dsh-inherit.cordis.yml";
|
|
8
|
+
function inheritSourceOf(profile, settingsFrom) {
|
|
9
|
+
if (settingsFrom === false) return null;
|
|
10
|
+
return settingsFrom === profile ? null : settingsFrom;
|
|
11
|
+
}
|
|
12
|
+
function stripEntries(text, skipIds) {
|
|
13
|
+
const skip = new Set(skipIds);
|
|
14
|
+
const kept = [];
|
|
15
|
+
let dropping = false;
|
|
16
|
+
for (const line of text.split("\n")) {
|
|
17
|
+
if (line.startsWith("- ")) {
|
|
18
|
+
const id = /^- id:\s*"?([^"\s]+)"?\s*$/.exec(line)?.[1];
|
|
19
|
+
dropping = id !== void 0 && skip.has(id);
|
|
20
|
+
}
|
|
21
|
+
if (!dropping) kept.push(line);
|
|
22
|
+
}
|
|
23
|
+
return kept.join("\n");
|
|
24
|
+
}
|
|
25
|
+
function writeInheritLayer(input) {
|
|
26
|
+
const source = path.join(dshProfileDir(input.source, input.home), "cordis.patch.yml");
|
|
27
|
+
let text;
|
|
28
|
+
try {
|
|
29
|
+
text = fs.readFileSync(source, "utf8");
|
|
30
|
+
} catch {
|
|
31
|
+
log.debug("\u6765\u6E90 profile \u6CA1\u6709\u53EF\u53E0\u7684\u914D\u7F6E\uFF0C\u8DF3\u8FC7", { source });
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const dir = path.join(input.cwd, AIPANEL_CACHE_DIR, "dsh");
|
|
35
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
36
|
+
const file = path.join(dir, INHERIT_LAYER_FILENAME);
|
|
37
|
+
fs.writeFileSync(file, stripEntries(text, INHERIT_SKIP_IDS), "utf8");
|
|
38
|
+
log.debug("\u5DF2\u53E0\u4E0A\u6765\u6E90 profile \u7684\u914D\u7F6E", { source, file, skipIds: INHERIT_SKIP_IDS });
|
|
39
|
+
return file;
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
INHERIT_LAYER_FILENAME,
|
|
43
|
+
INHERIT_SKIP_IDS,
|
|
44
|
+
inheritSourceOf,
|
|
45
|
+
stripEntries,
|
|
46
|
+
writeInheritLayer
|
|
47
|
+
};
|
package/es/types.d.ts
CHANGED
|
@@ -17,8 +17,25 @@ export type DeepSeekBusyEnter = BusyEnterBehavior;
|
|
|
17
17
|
export type DeepSeekProviderOptions = {
|
|
18
18
|
/** dsh 数据目录($DSH_HOME),默认跟随系统(~/.dsh) */
|
|
19
19
|
home?: string;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* dsh profile 名($DSH_HOME/profiles/<name>),默认 "web";AIPanel 侧插件与 web 进程都指向该 profile。
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ 该 profile 必须**先建好**:其 `dsh.profile.bundles` 里要有 `@deepseek-ai/dsh-web-app`。
|
|
24
|
+
* 缺失时 dsh 的 `plugin` 子命令会自己建出一个只有 `@deepseek-ai/dsh-base` 的空壳,
|
|
25
|
+
* 于是启动只会表现为"等 launch token 超时"(见 profile-check.ts 的预检与说明)。
|
|
26
|
+
*/
|
|
21
27
|
profile?: string;
|
|
28
|
+
/**
|
|
29
|
+
* 机器级设置(模型供应商 / 搜索源 / MCP)从哪个 profile 继承,作为一层 `--patch` 叠在目标 profile 之上。
|
|
30
|
+
*
|
|
31
|
+
* 默认 `web`(即 `providerOptions.profile` 的默认值):**默认就叠,用户不需要配**。dsh 没有
|
|
32
|
+
* "profile 继承 profile",不叠的话自建 profile 只会用建 profile 那一刻的快照,于是"我在 web 里
|
|
33
|
+
* 配过的东西这里看不到"。目标 profile 就是来源时自动跳过(等于不叠)。
|
|
34
|
+
*
|
|
35
|
+
* `false` = 不叠(只保留目标 profile 自己的配置)。每个界面自己的偏好(主题等)**永远不继承** ——
|
|
36
|
+
* 那类行跟着来源走会把界面锁死(见 settings-layer.ts)。
|
|
37
|
+
*/
|
|
38
|
+
settingsFrom?: string | false;
|
|
22
39
|
/** 默认 Agent 预设(dsh settings agent-presets.default,如 code/standard;新建会话的默认模式) */
|
|
23
40
|
agentPreset?: string;
|
|
24
41
|
/** 默认权限预设(dsh settings permission.defaultPreset) */
|
|
@@ -36,8 +53,9 @@ export type DeepSeekProviderOptions = {
|
|
|
36
53
|
*/
|
|
37
54
|
[key: string]: unknown;
|
|
38
55
|
};
|
|
39
|
-
/** 归一化后的 Provider 选项:诊断策略一定是完整的(Partial 已在 provider 内解析),profile 一定落到默认值 */
|
|
56
|
+
/** 归一化后的 Provider 选项:诊断策略一定是完整的(Partial 已在 provider 内解析),profile / settingsFrom 一定落到默认值 */
|
|
40
57
|
export type DeepSeekResolvedOptions = DeepSeekProviderOptions & {
|
|
41
58
|
profile: string;
|
|
59
|
+
settingsFrom: string | false;
|
|
42
60
|
diagnostics: DiagnosticsPolicy;
|
|
43
61
|
};
|
package/lib/constants.cjs
CHANGED
|
@@ -31,7 +31,8 @@ const DSH_LOOPBACK_HOST = "127.0.0.1";
|
|
|
31
31
|
const DSH_DEFAULT_PORT = 3080;
|
|
32
32
|
const DSH_DEFAULT_PROFILE = "web";
|
|
33
33
|
const DEFAULT_DEEPSEEK_PROVIDER_OPTIONS = {
|
|
34
|
-
profile: DSH_DEFAULT_PROFILE
|
|
34
|
+
profile: DSH_DEFAULT_PROFILE,
|
|
35
|
+
settingsFrom: DSH_DEFAULT_PROFILE
|
|
35
36
|
};
|
|
36
37
|
// Annotate the CommonJS export names for ESM import in node:
|
|
37
38
|
0 && (module.exports = {
|
package/lib/deepseek-web.cjs
CHANGED
|
@@ -41,6 +41,7 @@ class LaunchToken {
|
|
|
41
41
|
/** dsh 进程是否已 spawn:token 只可能在 spawn 后打印,超时窗口自 arm 起算 */
|
|
42
42
|
__publicField(this, "spawned", false);
|
|
43
43
|
__publicField(this, "windowTimer");
|
|
44
|
+
__publicField(this, "context");
|
|
44
45
|
/** 报错时把 dsh web 启动的原始日志作为一条日志整体输出(幂等:每实例只打一次) */
|
|
45
46
|
__publicField(this, "printed", false);
|
|
46
47
|
}
|
|
@@ -85,12 +86,24 @@ class LaunchToken {
|
|
|
85
86
|
/** 窗口到点:输出 dsh web 启动原始日志辅助诊断,再按未捕获 token 判定本次启动失败 */
|
|
86
87
|
expire() {
|
|
87
88
|
this.printStartupOutput();
|
|
89
|
+
const context = this.context?.();
|
|
90
|
+
const base = `dsh launch token was not captured from stdout within ${this.timeoutMs}ms (dsh >= 0.1.2 should print the "dsh web: http://127.0.0.1:<port>/?token=..." URL)`;
|
|
88
91
|
this.fail(
|
|
89
92
|
new Error(
|
|
90
|
-
|
|
93
|
+
context === void 0 || context.trim() === "" ? base : `${base}
|
|
94
|
+
${context}
|
|
95
|
+
\uFF08\u8FD9\u4E2A profile \u8D77\u4E0D\u4E86 Web UI \u65F6\u5C31\u662F\u8FD9\u4E2A\u75C7\u72B6\uFF1A\u5148\u786E\u8BA4\u5B83\u5EFA\u597D\u4E86\uFF09`
|
|
91
96
|
)
|
|
92
97
|
);
|
|
93
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* 附上"这次起的是哪个 profile"的上下文(provider 起进程前调用)。
|
|
101
|
+
* 只加在这里、不进 printStartupOutput:超时的那条错误要能自己说清 profile 与它的 bundle 列表,
|
|
102
|
+
* 否则症状永远只是"启动超时"(见 profile-check 的注释)。
|
|
103
|
+
*/
|
|
104
|
+
attachContext(provider) {
|
|
105
|
+
this.context = provider;
|
|
106
|
+
}
|
|
94
107
|
printStartupOutput() {
|
|
95
108
|
if (this.printed) return;
|
|
96
109
|
this.printed = true;
|
|
@@ -115,9 +128,12 @@ class LaunchToken {
|
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
130
|
function startDeepSeekWeb(options) {
|
|
118
|
-
const { port, hostname, cwd, patchPath, home, verbose, launchToken } = options;
|
|
131
|
+
const { port, hostname, cwd, patchPath, settingsPatchPath, home, verbose, launchToken } = options;
|
|
119
132
|
const profile = options.profile ?? import_constants.DSH_DEFAULT_PROFILE;
|
|
120
133
|
const args = ["--profile", profile];
|
|
134
|
+
if (settingsPatchPath) {
|
|
135
|
+
args.push("--patch", settingsPatchPath);
|
|
136
|
+
}
|
|
121
137
|
if (patchPath) {
|
|
122
138
|
args.push("--patch", patchPath);
|
|
123
139
|
}
|
package/lib/deepseek-web.d.ts
CHANGED
|
@@ -33,6 +33,13 @@ export declare class LaunchToken {
|
|
|
33
33
|
fail(err: Error): void;
|
|
34
34
|
/** 窗口到点:输出 dsh web 启动原始日志辅助诊断,再按未捕获 token 判定本次启动失败 */
|
|
35
35
|
private expire;
|
|
36
|
+
/**
|
|
37
|
+
* 附上"这次起的是哪个 profile"的上下文(provider 起进程前调用)。
|
|
38
|
+
* 只加在这里、不进 printStartupOutput:超时的那条错误要能自己说清 profile 与它的 bundle 列表,
|
|
39
|
+
* 否则症状永远只是"启动超时"(见 profile-check 的注释)。
|
|
40
|
+
*/
|
|
41
|
+
attachContext(provider: () => string): void;
|
|
42
|
+
private context?;
|
|
36
43
|
/** 报错时把 dsh web 启动的原始日志作为一条日志整体输出(幂等:每实例只打一次) */
|
|
37
44
|
private printed;
|
|
38
45
|
private printStartupOutput;
|
|
@@ -52,6 +59,11 @@ export interface DeepSeekWebOptions {
|
|
|
52
59
|
profile?: string;
|
|
53
60
|
/** cordis overlay 文件路径(--patch 注入 MCP client / aipanel 插件) */
|
|
54
61
|
patchPath?: string;
|
|
62
|
+
/**
|
|
63
|
+
* 继承层路径(--patch 叠来源 profile 的配置,见 settings-layer.ts)。
|
|
64
|
+
* 必须排在 `patchPath` **之前**:`--patch` 越靠后越赢,AIPanel 自己插的插件行要压过来源 profile。
|
|
65
|
+
*/
|
|
66
|
+
settingsPatchPath?: string;
|
|
55
67
|
/** dsh 数据目录(透传 DSH_HOME;缺省跟随 $DSH_HOME / ~/.dsh) */
|
|
56
68
|
home?: string;
|
|
57
69
|
/** 启用 verbose 模式 */
|
|
@@ -0,0 +1,77 @@
|
|
|
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_check_exports = {};
|
|
29
|
+
__export(profile_check_exports, {
|
|
30
|
+
DSH_WEB_APP_BUNDLE: () => DSH_WEB_APP_BUNDLE,
|
|
31
|
+
describeDshProfile: () => describeDshProfile,
|
|
32
|
+
inspectDshProfile: () => inspectDshProfile,
|
|
33
|
+
profileProblemText: () => profileProblemText
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(profile_check_exports);
|
|
36
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
37
|
+
var import_node_path = __toESM(require("node:path"));
|
|
38
|
+
const DSH_WEB_APP_BUNDLE = "@deepseek-ai/dsh-web-app";
|
|
39
|
+
function inspectDshProfile(profileDir) {
|
|
40
|
+
const manifest = import_node_path.default.join(profileDir, "package.json");
|
|
41
|
+
let parsed;
|
|
42
|
+
try {
|
|
43
|
+
parsed = JSON.parse(import_node_fs.default.readFileSync(manifest, "utf8"));
|
|
44
|
+
} catch {
|
|
45
|
+
return { ok: false, problem: "missing", bundles: [], manifest };
|
|
46
|
+
}
|
|
47
|
+
const declared = parsed?.dsh?.profile?.bundles;
|
|
48
|
+
const bundles = Array.isArray(declared) ? declared.filter((one) => typeof one === "string") : [];
|
|
49
|
+
if (!bundles.includes(DSH_WEB_APP_BUNDLE)) {
|
|
50
|
+
return { ok: false, problem: "no-web-app", bundles, manifest };
|
|
51
|
+
}
|
|
52
|
+
return { ok: true, problem: null, bundles, manifest };
|
|
53
|
+
}
|
|
54
|
+
function profileProblemText(inspection, profileDir, profile) {
|
|
55
|
+
const head = inspection.problem === "missing" ? `dsh profile "${profile}" \u8FD8\u4E0D\u5B58\u5728\uFF08\u627E\u4E0D\u5230 ${inspection.manifest}\uFF09` : `dsh profile "${profile}" \u91CC\u6CA1\u6709 Web \u5E94\u7528 bundle\uFF08${DSH_WEB_APP_BUNDLE}\uFF09`;
|
|
56
|
+
const bundles = inspection.bundles.length === 0 ? "\uFF08\u8BFB\u4E0D\u5230 bundle \u5217\u8868\uFF09" : `\u73B0\u6709 bundles\uFF1A${inspection.bundles.join("\u3001")}`;
|
|
57
|
+
return [
|
|
58
|
+
`${head}\uFF1A${profileDir}`,
|
|
59
|
+
` ${bundles}`,
|
|
60
|
+
" dsh \u5728 profile \u7F3A\u5931\u65F6\u4F1A\u81EA\u5DF1\u5EFA\u4E00\u4E2A\u53EA\u6709 @deepseek-ai/dsh-base \u7684\u7A7A\u58F3\uFF0C\u8D77\u6765\u4E0D\u4F1A\u6709\u754C\u9762\uFF1B",
|
|
61
|
+
" \u800C provider \u7684\u7F16\u6392\u662F\u300C\u5148\u88C5\u63D2\u4EF6\u3001\u518D\u8D77\u8FDB\u7A0B\u300D\uFF0C\u90A3\u4E00\u6B65\u4F1A\u628A\u7A7A\u58F3\u5EFA\u51FA\u6765\uFF0C\u75C7\u72B6\u53EA\u662F\u542F\u52A8\u8D85\u65F6\u3002",
|
|
62
|
+
" \u5148\u628A\u8FD9\u4E2A profile \u5EFA\u597D\uFF08\u5B83\u81EA\u5DF1\u7684\u5B89\u88C5\u6D41\u7A0B\uFF0C\u6216 `dsh <\u540D> --from-default-profile web`\uFF09\u518D\u91CD\u5F00\u3002"
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
function describeDshProfile(profileDir, profile) {
|
|
66
|
+
const inspection = inspectDshProfile(profileDir);
|
|
67
|
+
const bundles = inspection.bundles.length === 0 ? "\uFF08\u8BFB\u4E0D\u5230\uFF09" : inspection.bundles.join("\u3001");
|
|
68
|
+
return `profile: ${profile} (${profileDir})
|
|
69
|
+
bundles: ${bundles}`;
|
|
70
|
+
}
|
|
71
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
72
|
+
0 && (module.exports = {
|
|
73
|
+
DSH_WEB_APP_BUNDLE,
|
|
74
|
+
describeDshProfile,
|
|
75
|
+
inspectDshProfile,
|
|
76
|
+
profileProblemText
|
|
77
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** dsh 的 Web 应用 bundle(`dsh web` 的 profile 必有;纯终端类 profile 没有) */
|
|
2
|
+
export declare const DSH_WEB_APP_BUNDLE = "@deepseek-ai/dsh-web-app";
|
|
3
|
+
export type DshProfileProblem = "missing" | "no-web-app";
|
|
4
|
+
export interface DshProfileInspection {
|
|
5
|
+
/** 这个 profile 现在能不能起 Web UI */
|
|
6
|
+
readonly ok: boolean;
|
|
7
|
+
/** 不能时是哪一类问题;能时为 null */
|
|
8
|
+
readonly problem: DshProfileProblem | null;
|
|
9
|
+
/** profile 声明的 bundle 列表(读不到时为空数组) */
|
|
10
|
+
readonly bundles: readonly string[];
|
|
11
|
+
/** profile 清单文件路径(报错信息里给绝对路径,方便直接去看) */
|
|
12
|
+
readonly manifest: string;
|
|
13
|
+
}
|
|
14
|
+
/** 读 profile 清单并判断它是否具备启动 Web UI 的条件 */
|
|
15
|
+
export declare function inspectDshProfile(profileDir: string): DshProfileInspection;
|
|
16
|
+
/** 预检没过时给用户的说明(通用措辞:说清是什么、去哪看、怎么修) */
|
|
17
|
+
export declare function profileProblemText(inspection: DshProfileInspection, profileDir: string, profile: string): string;
|
|
18
|
+
/** 启动超时诊断用的一行上下文:profile 在哪、声明了哪些 bundle */
|
|
19
|
+
export declare function describeDshProfile(profileDir: string, profile: string): string;
|
package/lib/provider.cjs
CHANGED
|
@@ -30,6 +30,8 @@ var import_constants = require("./constants.cjs");
|
|
|
30
30
|
var import_api = require("./api.cjs");
|
|
31
31
|
var import_deepseek_web = require("./deepseek-web.cjs");
|
|
32
32
|
var import_profile = require("./profile.cjs");
|
|
33
|
+
var import_profile_check = require("./profile-check.cjs");
|
|
34
|
+
var import_settings_layer = require("./settings-layer.cjs");
|
|
33
35
|
var import_system = require("./system.cjs");
|
|
34
36
|
var import_dsh_install = require("./dsh-install.cjs");
|
|
35
37
|
const log = (0, import_node.createLogger)("DeepSeekWebProvider");
|
|
@@ -100,6 +102,14 @@ Please upgrade:
|
|
|
100
102
|
const launchToken = new import_deepseek_web.LaunchToken();
|
|
101
103
|
this.launchToken = launchToken;
|
|
102
104
|
this.api.setLaunchTokenSource(() => launchToken.wait());
|
|
105
|
+
launchToken.attachContext(() => (0, import_profile_check.describeDshProfile)(profileDir, this.opts.profile));
|
|
106
|
+
const profileCheck = (0, import_profile_check.inspectDshProfile)(profileDir);
|
|
107
|
+
if (!profileCheck.ok) {
|
|
108
|
+
const reason = (0, import_profile_check.profileProblemText)(profileCheck, profileDir, this.opts.profile);
|
|
109
|
+
log.error(reason);
|
|
110
|
+
launchToken.fail(new Error(reason));
|
|
111
|
+
throw new Error(reason);
|
|
112
|
+
}
|
|
103
113
|
const devClientDir = (0, import_dsh_install.resolveDevDshPackageSource)(import_meta.url, "dsh-client", "lib/client.js");
|
|
104
114
|
const providerVersion = (0, import_dsh_install.readProviderVersion)(import_meta.url);
|
|
105
115
|
const clientTarget = devClientDir ?? (providerVersion ? `${import_dsh_install.DSH_CLIENT_PACKAGE}@${providerVersion}` : `${import_dsh_install.DSH_CLIENT_PACKAGE}@latest`);
|
|
@@ -146,12 +156,15 @@ Please upgrade:
|
|
|
146
156
|
theme: this.uiTheme
|
|
147
157
|
});
|
|
148
158
|
const patchPath = (0, import_profile.writeDshOverlay)(options.cwd, overlay);
|
|
159
|
+
const inheritSource = (0, import_settings_layer.inheritSourceOf)(this.opts.profile, this.opts.settingsFrom);
|
|
160
|
+
const settingsPatchPath = inheritSource === null ? null : (0, import_settings_layer.writeInheritLayer)({ cwd: options.cwd, home: this.opts.home, source: inheritSource });
|
|
149
161
|
const proc = (0, import_deepseek_web.startDeepSeekWeb)({
|
|
150
162
|
port: options.port,
|
|
151
163
|
hostname: import_constants.DSH_LOOPBACK_HOST,
|
|
152
164
|
cwd: options.cwd,
|
|
153
165
|
profile: this.opts.profile,
|
|
154
166
|
patchPath,
|
|
167
|
+
...settingsPatchPath === null ? {} : { settingsPatchPath },
|
|
155
168
|
home: this.opts.home,
|
|
156
169
|
verbose: options.verbose,
|
|
157
170
|
launchToken
|
|
@@ -246,6 +259,8 @@ function resolveDeepSeekOptions(options) {
|
|
|
246
259
|
...import_constants.DEFAULT_DEEPSEEK_PROVIDER_OPTIONS,
|
|
247
260
|
home: po.home ?? options?.home,
|
|
248
261
|
profile: po.profile ?? options?.profile ?? import_constants.DSH_DEFAULT_PROFILE,
|
|
262
|
+
// 默认就叠(见 settings-layer.ts):用户不会去改配置,机器级设置只配一次是默认预期。
|
|
263
|
+
settingsFrom: po.settingsFrom === false ? false : typeof po.settingsFrom === "string" ? po.settingsFrom : import_constants.DSH_DEFAULT_PROFILE,
|
|
249
264
|
agentPreset: po.agentPreset ?? options?.agentPreset,
|
|
250
265
|
permissionPreset: po.permissionPreset ?? options?.permissionPreset,
|
|
251
266
|
busyEnter: po.busyEnter ?? options?.busyEnter,
|
|
@@ -0,0 +1,84 @@
|
|
|
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 settings_layer_exports = {};
|
|
29
|
+
__export(settings_layer_exports, {
|
|
30
|
+
INHERIT_LAYER_FILENAME: () => INHERIT_LAYER_FILENAME,
|
|
31
|
+
INHERIT_SKIP_IDS: () => INHERIT_SKIP_IDS,
|
|
32
|
+
inheritSourceOf: () => inheritSourceOf,
|
|
33
|
+
stripEntries: () => stripEntries,
|
|
34
|
+
writeInheritLayer: () => writeInheritLayer
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(settings_layer_exports);
|
|
37
|
+
var import_node_fs = __toESM(require("node:fs"));
|
|
38
|
+
var import_node_path = __toESM(require("node:path"));
|
|
39
|
+
var import_node = require("@aipanel/core/node");
|
|
40
|
+
var import_dsh_install = require("./dsh-install.cjs");
|
|
41
|
+
const log = (0, import_node.createLogger)("DeepSeekSettings");
|
|
42
|
+
const INHERIT_SKIP_IDS = ["ui-theme"];
|
|
43
|
+
const INHERIT_LAYER_FILENAME = "dsh-inherit.cordis.yml";
|
|
44
|
+
function inheritSourceOf(profile, settingsFrom) {
|
|
45
|
+
if (settingsFrom === false) return null;
|
|
46
|
+
return settingsFrom === profile ? null : settingsFrom;
|
|
47
|
+
}
|
|
48
|
+
function stripEntries(text, skipIds) {
|
|
49
|
+
const skip = new Set(skipIds);
|
|
50
|
+
const kept = [];
|
|
51
|
+
let dropping = false;
|
|
52
|
+
for (const line of text.split("\n")) {
|
|
53
|
+
if (line.startsWith("- ")) {
|
|
54
|
+
const id = /^- id:\s*"?([^"\s]+)"?\s*$/.exec(line)?.[1];
|
|
55
|
+
dropping = id !== void 0 && skip.has(id);
|
|
56
|
+
}
|
|
57
|
+
if (!dropping) kept.push(line);
|
|
58
|
+
}
|
|
59
|
+
return kept.join("\n");
|
|
60
|
+
}
|
|
61
|
+
function writeInheritLayer(input) {
|
|
62
|
+
const source = import_node_path.default.join((0, import_dsh_install.dshProfileDir)(input.source, input.home), "cordis.patch.yml");
|
|
63
|
+
let text;
|
|
64
|
+
try {
|
|
65
|
+
text = import_node_fs.default.readFileSync(source, "utf8");
|
|
66
|
+
} catch {
|
|
67
|
+
log.debug("\u6765\u6E90 profile \u6CA1\u6709\u53EF\u53E0\u7684\u914D\u7F6E\uFF0C\u8DF3\u8FC7", { source });
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const dir = import_node_path.default.join(input.cwd, import_node.AIPANEL_CACHE_DIR, "dsh");
|
|
71
|
+
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
72
|
+
const file = import_node_path.default.join(dir, INHERIT_LAYER_FILENAME);
|
|
73
|
+
import_node_fs.default.writeFileSync(file, stripEntries(text, INHERIT_SKIP_IDS), "utf8");
|
|
74
|
+
log.debug("\u5DF2\u53E0\u4E0A\u6765\u6E90 profile \u7684\u914D\u7F6E", { source, file, skipIds: INHERIT_SKIP_IDS });
|
|
75
|
+
return file;
|
|
76
|
+
}
|
|
77
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
78
|
+
0 && (module.exports = {
|
|
79
|
+
INHERIT_LAYER_FILENAME,
|
|
80
|
+
INHERIT_SKIP_IDS,
|
|
81
|
+
inheritSourceOf,
|
|
82
|
+
stripEntries,
|
|
83
|
+
writeInheritLayer
|
|
84
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** 不跟着来源走的那几行(每个界面自己的偏好);理由见文件头 */
|
|
2
|
+
export declare const INHERIT_SKIP_IDS: readonly string[];
|
|
3
|
+
/** 生成层落在项目缓存目录,与 AIPanel 自己的 overlay 同处 */
|
|
4
|
+
export declare const INHERIT_LAYER_FILENAME = "dsh-inherit.cordis.yml";
|
|
5
|
+
/**
|
|
6
|
+
* 该从哪个 profile 继承。
|
|
7
|
+
* @param settingsFrom 解析后的选项:profile 名 / `false`(不叠)
|
|
8
|
+
* @returns 源 profile 名;`null` = 不叠(关掉了,或目标就是它自己)
|
|
9
|
+
*/
|
|
10
|
+
export declare function inheritSourceOf(profile: string, settingsFrom: string | false): string | null;
|
|
11
|
+
/**
|
|
12
|
+
* 按**顶层条目**剥掉若干 `- id:` 块(与 dsh-workbench 启动器里那段 awk 同口径:从命中的 `- ` 行
|
|
13
|
+
* 一路丢到下一个顶层 `- ` 为止)。手写而不是上 YAML 库:这一层只是转交一份文本,没必要为它引入依赖,
|
|
14
|
+
* 也不能因为来源文件里有 `!!js` 之类的 dsh 扩展标签就解析失败。
|
|
15
|
+
*/
|
|
16
|
+
export declare function stripEntries(text: string, skipIds: readonly string[]): string;
|
|
17
|
+
/**
|
|
18
|
+
* 写出继承层并返回它的路径;来源不存在/读不动时返回 `null`(**不阻断启动**:少了它只是回到老行为)。
|
|
19
|
+
*/
|
|
20
|
+
export declare function writeInheritLayer(input: {
|
|
21
|
+
cwd: string;
|
|
22
|
+
home?: string | undefined;
|
|
23
|
+
source: string;
|
|
24
|
+
}): string | null;
|
package/lib/types.d.ts
CHANGED
|
@@ -17,8 +17,25 @@ export type DeepSeekBusyEnter = BusyEnterBehavior;
|
|
|
17
17
|
export type DeepSeekProviderOptions = {
|
|
18
18
|
/** dsh 数据目录($DSH_HOME),默认跟随系统(~/.dsh) */
|
|
19
19
|
home?: string;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* dsh profile 名($DSH_HOME/profiles/<name>),默认 "web";AIPanel 侧插件与 web 进程都指向该 profile。
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ 该 profile 必须**先建好**:其 `dsh.profile.bundles` 里要有 `@deepseek-ai/dsh-web-app`。
|
|
24
|
+
* 缺失时 dsh 的 `plugin` 子命令会自己建出一个只有 `@deepseek-ai/dsh-base` 的空壳,
|
|
25
|
+
* 于是启动只会表现为"等 launch token 超时"(见 profile-check.ts 的预检与说明)。
|
|
26
|
+
*/
|
|
21
27
|
profile?: string;
|
|
28
|
+
/**
|
|
29
|
+
* 机器级设置(模型供应商 / 搜索源 / MCP)从哪个 profile 继承,作为一层 `--patch` 叠在目标 profile 之上。
|
|
30
|
+
*
|
|
31
|
+
* 默认 `web`(即 `providerOptions.profile` 的默认值):**默认就叠,用户不需要配**。dsh 没有
|
|
32
|
+
* "profile 继承 profile",不叠的话自建 profile 只会用建 profile 那一刻的快照,于是"我在 web 里
|
|
33
|
+
* 配过的东西这里看不到"。目标 profile 就是来源时自动跳过(等于不叠)。
|
|
34
|
+
*
|
|
35
|
+
* `false` = 不叠(只保留目标 profile 自己的配置)。每个界面自己的偏好(主题等)**永远不继承** ——
|
|
36
|
+
* 那类行跟着来源走会把界面锁死(见 settings-layer.ts)。
|
|
37
|
+
*/
|
|
38
|
+
settingsFrom?: string | false;
|
|
22
39
|
/** 默认 Agent 预设(dsh settings agent-presets.default,如 code/standard;新建会话的默认模式) */
|
|
23
40
|
agentPreset?: string;
|
|
24
41
|
/** 默认权限预设(dsh settings permission.defaultPreset) */
|
|
@@ -36,8 +53,9 @@ export type DeepSeekProviderOptions = {
|
|
|
36
53
|
*/
|
|
37
54
|
[key: string]: unknown;
|
|
38
55
|
};
|
|
39
|
-
/** 归一化后的 Provider 选项:诊断策略一定是完整的(Partial 已在 provider 内解析),profile 一定落到默认值 */
|
|
56
|
+
/** 归一化后的 Provider 选项:诊断策略一定是完整的(Partial 已在 provider 内解析),profile / settingsFrom 一定落到默认值 */
|
|
40
57
|
export type DeepSeekResolvedOptions = DeepSeekProviderOptions & {
|
|
41
58
|
profile: string;
|
|
59
|
+
settingsFrom: string | false;
|
|
42
60
|
diagnostics: DiagnosticsPolicy;
|
|
43
61
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aipanel/provider-deepseek",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"registry": "https://registry.npmjs.org/"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@aipanel/core": "1.3.
|
|
24
|
+
"@aipanel/core": "1.3.12",
|
|
25
25
|
"execa": "^9.6.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|