@fa-software/semi2-dsh 0.0.13 → 0.0.14-preview.20260922151653
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/README.md +20 -7
- package/lib/api/generated/documents.js +10 -1
- package/lib/api/generated/schema.js +2 -9
- package/lib/api/index.js +13 -0
- package/lib/client.js +54 -48
- package/lib/client.js.map +1 -1
- package/lib/contract.js +6 -0
- package/lib/domains/models/domain.js +11 -4
- package/lib/domains/models/web-search.js +61 -0
- package/lib/domains/redmine/domain.js +139 -0
- package/lib/domains/redmine/index.js +57 -0
- package/lib/domains/skills/candidates.js +4 -2
- package/lib/domains/skills/domain.js +5 -3
- package/lib/domains/workspace/domain.js +3 -2
- package/lib/hub/facts.js +1 -0
- package/lib/index.js +10 -11
- package/lib/service/audit.js +21 -7
- package/lib/service/config-service.js +9 -22
- package/lib/service/lifecycle.js +32 -34
- package/lib/service/namespaces.js +46 -16
- package/lib/service/ports.js +36 -13
- package/lib/service/publish.js +8 -8
- package/lib/service/registry.js +2 -0
- package/lib/service/sessions.js +90 -0
- package/lib/service/settings-sections.js +23 -62
- package/lib/types/api/generated/documents.d.ts +1 -1
- package/lib/types/api/generated/graphql.d.ts +27 -5
- package/lib/types/api/generated/schema.d.ts +265 -60
- package/lib/types/api/index.d.ts +13 -1
- package/lib/types/contract.d.ts +11 -0
- package/lib/types/domains/models/web-search.d.ts +8 -0
- package/lib/types/domains/redmine/domain.d.ts +59 -0
- package/lib/types/domains/redmine/index.d.ts +10 -0
- package/lib/types/domains/skills/domain.d.ts +1 -1
- package/lib/types/domains/types.d.ts +8 -2
- package/lib/types/hub/facts.d.ts +18 -0
- package/lib/types/index.d.ts +28 -24
- package/lib/types/service/audit.d.ts +10 -0
- package/lib/types/service/config-service.d.ts +3 -1
- package/lib/types/service/lifecycle.d.ts +5 -0
- package/lib/types/service/namespaces.d.ts +15 -17
- package/lib/types/service/ports.d.ts +19 -15
- package/lib/types/service/publish.d.ts +6 -1
- package/lib/types/service/sessions.d.ts +8 -0
- package/lib/types/service/settings-sections.d.ts +5 -14
- package/lib/types/web/routes.d.ts +4 -2
- package/lib/types/web/welcome-ack.d.ts +3 -3
- package/lib/web/routes.js +25 -1
- package/lib/web/welcome-ack.js +5 -5
- package/package.json +19 -11
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { DomainHost, DomainService, LoadRun, RevertRun } from '../types.js';
|
|
2
|
+
import type { Semi2ConfigState } from '../../hub/facts.js';
|
|
3
|
+
/** MCP 服务的命名空间(工具名 = `mcp__redmine__<tool>`)。 */
|
|
4
|
+
export declare const REDMINE_SERVER_NAME = "redmine";
|
|
5
|
+
/** 一次挂载的完整配置(形状由官方 mcp-client 的 Config 决定,这里逐字段收口)。 */
|
|
6
|
+
export interface RedmineMcpConfig {
|
|
7
|
+
transport: 'stdio';
|
|
8
|
+
serverName: string;
|
|
9
|
+
command: string;
|
|
10
|
+
args: string[];
|
|
11
|
+
env: Record<string, string>;
|
|
12
|
+
cwd: string;
|
|
13
|
+
toolCallTimeoutMs: number;
|
|
14
|
+
failOnStartupError: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** 挂载句柄:就绪面(激活 + 首次连接与工具发现)+ 官方 fiber 的卸载面。 */
|
|
17
|
+
export interface MountedServer {
|
|
18
|
+
/** true = 工具已注册;false = 到上限仍未就绪或激活失败(光纤留着,官方那边会自己重连)。 */
|
|
19
|
+
ready: Promise<boolean>;
|
|
20
|
+
dispose(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/** 领域依赖的运行面能力(插件上下文与 process.env 都在 index.ts 里收口,领域自己不认识 cordis)。 */
|
|
23
|
+
export interface RedmineFaces {
|
|
24
|
+
/** 挂一根官方 mcp-client 光纤;缺闭包 / 配置不合法时 reject(只 warn 降级)。 */
|
|
25
|
+
mount(config: RedmineMcpConfig): Promise<MountedServer>;
|
|
26
|
+
/** 起进程的命令与工作目录(env 覆盖、已登记工作区)。 */
|
|
27
|
+
command(): string;
|
|
28
|
+
cwd(): string;
|
|
29
|
+
}
|
|
30
|
+
/** boot 事实 → 挂载配置;密钥只进子进程 env,不落盘、不进日志。 */
|
|
31
|
+
export declare function redmineMcpConfig(baseUrl: string, apiKey: string, faces: Pick<RedmineFaces, 'command' | 'cwd'>): RedmineMcpConfig;
|
|
32
|
+
export declare class RedmineDomain implements DomainService {
|
|
33
|
+
private readonly host;
|
|
34
|
+
private readonly faces;
|
|
35
|
+
readonly id: "redmine";
|
|
36
|
+
private mounted;
|
|
37
|
+
private degraded;
|
|
38
|
+
private pending;
|
|
39
|
+
constructor(host: DomainHost, faces: RedmineFaces);
|
|
40
|
+
/**
|
|
41
|
+
* boot 事实落地:
|
|
42
|
+
* - 块缺失 / null(读取失败)→ 只 warn,保持现状(不动已挂的服务);
|
|
43
|
+
* - 两项齐备 → 配置没变就不重挂,变了先卸再挂;
|
|
44
|
+
* - 任一项 null(权威未配置)→ 卸载。
|
|
45
|
+
*/
|
|
46
|
+
applyBoot(run: LoadRun): Promise<void>;
|
|
47
|
+
/** 登出 / 服务端整体撤下:Redmine 工具随身份一起收走。 */
|
|
48
|
+
revert(_run: RevertRun): Promise<void>;
|
|
49
|
+
private unmount;
|
|
50
|
+
statusFields(state: Semi2ConfigState): Record<string, string>;
|
|
51
|
+
summary(state: Semi2ConfigState): string | null;
|
|
52
|
+
health(): {
|
|
53
|
+
state: "ok";
|
|
54
|
+
note: string;
|
|
55
|
+
} | {
|
|
56
|
+
state: "degraded";
|
|
57
|
+
note: string;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { DomainPlugin } from '../types.js';
|
|
3
|
+
import { type RedmineFaces } from './domain.js';
|
|
4
|
+
/** 起进程的命令:镜像里在 PATH 上;npm 消费者可用 `SEMI2_REDMINE_MCP_BIN` 指到别处(同 CodeGraph 口径)。 */
|
|
5
|
+
export declare function redmineMcpCommand(env: NodeJS.ProcessEnv): string;
|
|
6
|
+
/** 子进程工作目录 = 本面工作目录(同 CodeGraph 挂载行)。 */
|
|
7
|
+
export declare function redmineMcpCwd(env: NodeJS.ProcessEnv): string;
|
|
8
|
+
/** 运行面能力:动态 import 官方包 + 在本领域的 ctx 上挂一根光纤(dispose 由领域持有)。 */
|
|
9
|
+
export declare function createRedmineFaces(ctx: Context): RedmineFaces;
|
|
10
|
+
export declare const redmineDomain: DomainPlugin;
|
|
@@ -13,7 +13,7 @@ export declare class SkillsDomain implements DomainService, SkillsPeer {
|
|
|
13
13
|
invalidate(): void;
|
|
14
14
|
skills(): RuntimeSkillFact[] | null;
|
|
15
15
|
/**
|
|
16
|
-
* 控制台技能目录:`
|
|
16
|
+
* 控制台技能目录:`runtimeSkillCatalog` 为 null/undefined 都算「没拿到权威目录」——null 只降级该块,
|
|
17
17
|
* null ≠ 空数组(provider 据此报 complete:false,dsh 才不把抖动缓存成空目录)。
|
|
18
18
|
*/
|
|
19
19
|
applyBoot(run: LoadRun): Promise<void>;
|
|
@@ -4,7 +4,7 @@ import type { RuntimeSkillFact, RuntimeSkillFileContentFact, Semi2ConfigState }
|
|
|
4
4
|
import type { CompiledConfiguration, RuntimeProject } from '../hub/compile.js';
|
|
5
5
|
import type { WorkspaceEntry } from '../hub/workspace-book.js';
|
|
6
6
|
import type { Ports, SettingsLike } from '../service/ports.js';
|
|
7
|
-
/**
|
|
7
|
+
/** 本插件写过什么的归属表(插件自身设置段;models 记 routes/deepseek、secrets 记 credentials)。 */
|
|
8
8
|
export interface OwnedFacts {
|
|
9
9
|
/** 注入到 `llm-pi-ai` 的路由(最终落地的键)。 */
|
|
10
10
|
routes: string[];
|
|
@@ -12,6 +12,8 @@ export interface OwnedFacts {
|
|
|
12
12
|
credentials: string[];
|
|
13
13
|
/** 是否覆盖着内置 `llm-deepseek` 段。 */
|
|
14
14
|
deepseek: boolean;
|
|
15
|
+
/** 写入官方 DeepSeek 搜索段的密钥引用;null = 当前值归用户或未写。 */
|
|
16
|
+
deepseekSearchKeyEnv: string | null;
|
|
15
17
|
}
|
|
16
18
|
/** 附件读取结果:null = 本次放弃物化(调用方保留正文);空数组 = 权威「没有附件」。 */
|
|
17
19
|
export interface SkillsFileOutcome {
|
|
@@ -31,6 +33,9 @@ export interface SecretsPeer {
|
|
|
31
33
|
/** 自画像领域没有跨领域被调的成员(注入段由领域自己注册);占位同 SecretsPeer 口径。 */
|
|
32
34
|
export interface SelfPortraitPeer {
|
|
33
35
|
}
|
|
36
|
+
/** Redmine 领域没有跨领域被调的成员(挂载与卸载都由它自己的生命周期驱动);占位同 SecretsPeer 口径。 */
|
|
37
|
+
export interface RedminePeer {
|
|
38
|
+
}
|
|
34
39
|
export interface SkillsPeer {
|
|
35
40
|
/** 当前控制台技能目录(null = 没拿到权威目录,≠ 空目录)。 */
|
|
36
41
|
skills(): RuntimeSkillFact[] | null;
|
|
@@ -89,6 +94,7 @@ export interface DomainPeers {
|
|
|
89
94
|
workspace: WorkspacePeer;
|
|
90
95
|
'default-model': DefaultModelPeer;
|
|
91
96
|
'self-portrait': SelfPortraitPeer;
|
|
97
|
+
redmine: RedminePeer;
|
|
92
98
|
}
|
|
93
99
|
/** 一轮 boot 装配的共享上下文(编排层创建,按注册表顺序流经各领域)。 */
|
|
94
100
|
export interface LoadRun {
|
|
@@ -170,4 +176,4 @@ export interface DomainPlugin {
|
|
|
170
176
|
readonly inject?: readonly string[];
|
|
171
177
|
apply(ctx: Context, config: DomainMountConfig): void;
|
|
172
178
|
}
|
|
173
|
-
export type DomainId = 'models' | 'secrets' | 'skills' | 'workspace' | 'default-model' | 'self-portrait';
|
|
179
|
+
export type DomainId = 'models' | 'secrets' | 'skills' | 'workspace' | 'default-model' | 'self-portrait' | 'redmine';
|
package/lib/types/hub/facts.d.ts
CHANGED
|
@@ -22,6 +22,11 @@ export interface RuntimeSkillFileContentFact {
|
|
|
22
22
|
mimeType: string;
|
|
23
23
|
isExecutable: boolean;
|
|
24
24
|
}
|
|
25
|
+
/** dsh 调用策略:两个目录各自独立,false/false 的技能不会从 hub 下发。 */
|
|
26
|
+
export interface RuntimeSkillInvocationFact {
|
|
27
|
+
modelInvocable: boolean;
|
|
28
|
+
userInvocable: boolean;
|
|
29
|
+
}
|
|
25
30
|
/** 运行面下发的技能事实;`content` 是正文(frontmatter 已剥),是否对本 cwd 生效由 provider 裁定。 */
|
|
26
31
|
export interface RuntimeSkillFact {
|
|
27
32
|
id: string;
|
|
@@ -30,6 +35,9 @@ export interface RuntimeSkillFact {
|
|
|
30
35
|
name: string;
|
|
31
36
|
description: string;
|
|
32
37
|
whenToUse: string | null;
|
|
38
|
+
invocation: RuntimeSkillInvocationFact;
|
|
39
|
+
/** dsh 标准 metadata;null = 未配置。 */
|
|
40
|
+
metadata: Record<string, unknown> | null;
|
|
33
41
|
content: string;
|
|
34
42
|
version: number;
|
|
35
43
|
/** 附件清单(boot 只给清单,字节走 `skillFiles`);无附件为空数组。 */
|
|
@@ -41,6 +49,14 @@ export interface RuntimeIdentity {
|
|
|
41
49
|
username: string;
|
|
42
50
|
displayName: string;
|
|
43
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Redmine 接缝事实:地址来自全局配置、密钥来自本人;两项齐备运行面才挂只读 MCP 服务。
|
|
54
|
+
* 与服务端契约同口径——任一为 null 就是权威「这一项没配」。
|
|
55
|
+
*/
|
|
56
|
+
export interface RuntimeRedmineFact {
|
|
57
|
+
baseUrl: string | null;
|
|
58
|
+
apiKey: string | null;
|
|
59
|
+
}
|
|
44
60
|
export interface Semi2ConfigState {
|
|
45
61
|
status: ConfigStatus;
|
|
46
62
|
/** 最近一次成功读取的时间(ISO),未成功过为 null。 */
|
|
@@ -61,6 +77,8 @@ export interface Semi2ConfigState {
|
|
|
61
77
|
* 注入段按它现读——两种空都不注入。
|
|
62
78
|
*/
|
|
63
79
|
selfPortrait: string | null;
|
|
80
|
+
/** Redmine 地址 + 本人密钥:null = 没拿到(不改变现状),任一字段 null = 权威未配置(不挂服务)。 */
|
|
81
|
+
redmine: RuntimeRedmineFact | null;
|
|
64
82
|
/** 已登记工作区命中的项目(含生效绑定,按 slug 现取并缓存);会话按 cwd 经 `projectFor` 匹配。 */
|
|
65
83
|
projects: RuntimeProject[];
|
|
66
84
|
/** 已登记工作区(dsh 工作区 → git 项目映射);未接入工作区服务时为单条隐式条目。 */
|
package/lib/types/index.d.ts
CHANGED
|
@@ -5,47 +5,51 @@ export type { RuntimeIdentity, RuntimeSkillFact, RuntimeSkillFileContentFact, Ru
|
|
|
5
5
|
export type { ConfigStatus, Semi2Config, Semi2Audit, Semi2Health, Semi2Session, } from './service/config-service.js';
|
|
6
6
|
export type { HeadlessModelOutcome } from './domains/types.js';
|
|
7
7
|
export type { Semi2Surface } from './hub/facts.js';
|
|
8
|
-
export { SEMI2_RUNTIME_SERVICE, SEMI2_SECTION_ORDERS, runtimeFromCnbEnv, runtimeFromContainerEnv, semi2SectionOrder, } from './contract.js';
|
|
8
|
+
export { SEMI2_RUNTIME_SERVICE, SEMI2_SECTION_ORDERS, SEMI2_SETTINGS_ENTRY, runtimeFromCnbEnv, runtimeFromContainerEnv, semi2SectionOrder, } from './contract.js';
|
|
9
9
|
export type { SectionOrderSource, Semi2Credentials, Semi2Platform, Semi2Runtime, Semi2SectionKey, } from './contract.js';
|
|
10
10
|
import './events.js';
|
|
11
11
|
export declare const name = "semi2-dsh";
|
|
12
12
|
/**
|
|
13
13
|
* 可调参数:默认值 = 各模块曾经的常量;bundle patch 行不写 config,消费方 overlay 才覆盖。
|
|
14
14
|
* 「config 明确值 → 环境变量 → 内置常量」的取值顺序在 apply 里一次归一。
|
|
15
|
+
*
|
|
16
|
+
* 状态 / 健康 / 工作区 tab / 归属表 / 工作区映射(`STATE_CONFIG_FIELDS`)同在这一段里,但全部声明为
|
|
17
|
+
* volatile(可实时写、不重挂载):dsh 的 `describe()` 只认有 volatile 字段的条目,本插件的设置段
|
|
18
|
+
* 靠它才存在。这些字段一律经 `describe()` 读写,不在 `apply` 里当普通值取(volatile 字段在 config 上是引用)。
|
|
15
19
|
*/
|
|
16
|
-
export declare const Config: z<Schemastery.ObjectS<{
|
|
20
|
+
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
17
21
|
/** 等运行面契约(`semi2Runtime`)出现的上限:超时按宿主直跑处理。 */
|
|
18
|
-
contractTimeoutMs: z<number, number>;
|
|
22
|
+
contractTimeoutMs: z<number, number, "defined">;
|
|
19
23
|
/** 等领域装配的上限:超时的领域记「本面不提供该能力」。 */
|
|
20
|
-
domainAttachTimeoutMs: z<number, number>;
|
|
24
|
+
domainAttachTimeoutMs: z<number, number, "defined">;
|
|
21
25
|
/** 等 settings 服务的上限:本面无该服务时不阻塞启动。 */
|
|
22
|
-
settingsTimeoutMs: z<number, number>;
|
|
23
|
-
/**
|
|
24
|
-
namespaceWaitMs: z<number, number>;
|
|
26
|
+
settingsTimeoutMs: z<number, number, "defined">;
|
|
27
|
+
/** 等设置段可读可写(条目 ACTIVE 且声明了 volatile 字段)的上限。 */
|
|
28
|
+
namespaceWaitMs: z<number, number, "defined">;
|
|
25
29
|
/** 凭据存储首次读盘的重试次数与间隔。 */
|
|
26
|
-
credentialRetryTries: z<number, number>;
|
|
27
|
-
credentialRetryIntervalMs: z<number, number>;
|
|
30
|
+
credentialRetryTries: z<number, number, "defined">;
|
|
31
|
+
credentialRetryIntervalMs: z<number, number, "defined">;
|
|
28
32
|
/** webServer 在而校验面迟迟不出现时,多久补一条诊断日志。 */
|
|
29
|
-
webFenceTimeoutMs: z<number, number>;
|
|
30
|
-
/** 登录 / 登出 / 健康路由的请求体上限(字节)。 */
|
|
31
|
-
webRouteBodyLimitBytes: z<number, number>;
|
|
32
|
-
}
|
|
33
|
+
webFenceTimeoutMs: z<number, number, "defined">;
|
|
34
|
+
/** 登录 / 登出 / 同步 / 健康路由的请求体上限(字节)。 */
|
|
35
|
+
webRouteBodyLimitBytes: z<number, number, "defined">;
|
|
36
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
33
37
|
/** 等运行面契约(`semi2Runtime`)出现的上限:超时按宿主直跑处理。 */
|
|
34
|
-
contractTimeoutMs: z<number, number>;
|
|
38
|
+
contractTimeoutMs: z<number, number, "defined">;
|
|
35
39
|
/** 等领域装配的上限:超时的领域记「本面不提供该能力」。 */
|
|
36
|
-
domainAttachTimeoutMs: z<number, number>;
|
|
40
|
+
domainAttachTimeoutMs: z<number, number, "defined">;
|
|
37
41
|
/** 等 settings 服务的上限:本面无该服务时不阻塞启动。 */
|
|
38
|
-
settingsTimeoutMs: z<number, number>;
|
|
39
|
-
/**
|
|
40
|
-
namespaceWaitMs: z<number, number>;
|
|
42
|
+
settingsTimeoutMs: z<number, number, "defined">;
|
|
43
|
+
/** 等设置段可读可写(条目 ACTIVE 且声明了 volatile 字段)的上限。 */
|
|
44
|
+
namespaceWaitMs: z<number, number, "defined">;
|
|
41
45
|
/** 凭据存储首次读盘的重试次数与间隔。 */
|
|
42
|
-
credentialRetryTries: z<number, number>;
|
|
43
|
-
credentialRetryIntervalMs: z<number, number>;
|
|
46
|
+
credentialRetryTries: z<number, number, "defined">;
|
|
47
|
+
credentialRetryIntervalMs: z<number, number, "defined">;
|
|
44
48
|
/** webServer 在而校验面迟迟不出现时,多久补一条诊断日志。 */
|
|
45
|
-
webFenceTimeoutMs: z<number, number>;
|
|
46
|
-
/** 登录 / 登出 / 健康路由的请求体上限(字节)。 */
|
|
47
|
-
webRouteBodyLimitBytes: z<number, number>;
|
|
48
|
-
}
|
|
49
|
+
webFenceTimeoutMs: z<number, number, "defined">;
|
|
50
|
+
/** 登录 / 登出 / 同步 / 健康路由的请求体上限(字节)。 */
|
|
51
|
+
webRouteBodyLimitBytes: z<number, number, "defined">;
|
|
52
|
+
}>>, "plain">;
|
|
49
53
|
export type Config = Schemastery.TypeT<typeof Config>;
|
|
50
54
|
/** apply 内归一后的不可变参数(配置面 → 编排 / web 面的唯一形状)。 */
|
|
51
55
|
export interface InstallOptions {
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { OrchestratorInternals } from './orchestrator.js';
|
|
2
2
|
import type { RuntimeEventReport } from '../api/index.js';
|
|
3
|
+
/** 上报结果:调用方(NPC 面的 `semi2Audit` 出口)要据此记一行「未接受」。 */
|
|
4
|
+
export interface ReportOutcome {
|
|
5
|
+
ok: boolean;
|
|
6
|
+
code: string | null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 上报一条运行面事件并回结果:本面标识(`face`)与运行面契约里的任务引用在这里补齐,
|
|
10
|
+
* 调用方(会话订阅 / 适配器)不必各自知道这两个事实从哪来。
|
|
11
|
+
*/
|
|
12
|
+
export declare function reportEventResult(engine: OrchestratorInternals, event: RuntimeEventReport): Promise<ReportOutcome>;
|
|
3
13
|
/** 生命周期事件:动作名与结果名都用 hub SDL 的枚举名,两侧不各维护一张映射表。 */
|
|
4
14
|
export declare function reportEvent(engine: OrchestratorInternals, event: RuntimeEventReport): Promise<void>;
|
|
5
15
|
/** 本面标识:契约里有就用它;宿主直跑没有契约,记 host。 */
|
|
@@ -22,7 +22,7 @@ export interface Semi2Config {
|
|
|
22
22
|
cwd?: string;
|
|
23
23
|
}): Promise<HeadlessModelOutcome>;
|
|
24
24
|
}
|
|
25
|
-
/** 动作面(`ctx.semi2Session`):设置页登录 /
|
|
25
|
+
/** 动作面(`ctx.semi2Session`):设置页登录 / 登出 / 同步;web 路由仍由入口传参取(同 fiber 严格查找拿不到)。 */
|
|
26
26
|
export interface Semi2Session {
|
|
27
27
|
/** 一步换取用户密钥 → 写入 dsh credentials 存储 → 立即重新读取;失败抛(code 由 UI 展示)。 */
|
|
28
28
|
login(input: {
|
|
@@ -34,6 +34,8 @@ export interface Semi2Session {
|
|
|
34
34
|
}>;
|
|
35
35
|
/** 清掉登录凭据,并把本插件写过的本地条目整体回收;部署面凭据不受影响。 */
|
|
36
36
|
logout(): Promise<void>;
|
|
37
|
+
/** 界面「同步」:`workspace:<slug>` 只同步该工作区,其余(含空串)整体重载;失败只 warn。 */
|
|
38
|
+
sync(scope: string): Promise<void>;
|
|
37
39
|
}
|
|
38
40
|
/** 诊断面(`ctx.semi2Health`):健康快照,诊断路由与设置页健康行共用。 */
|
|
39
41
|
export interface Semi2Health {
|
|
@@ -3,6 +3,11 @@ import type { OrchestratorInternals } from './orchestrator.js';
|
|
|
3
3
|
export declare function start(engine: OrchestratorInternals): Promise<void>;
|
|
4
4
|
/** 手动重新读取并应用;未配凭据时只重解析连接(登录/登出显式重走两条路)。 */
|
|
5
5
|
export declare function reload(engine: OrchestratorInternals): Promise<ReturnType<OrchestratorInternals['state']>>;
|
|
6
|
+
/**
|
|
7
|
+
* 界面「同步」动作:`workspace:<slug>` 只同步那一个工作区,其余(含空串)整体重载。
|
|
8
|
+
* 两条路都把结果回写状态段;失败只 warn(面板上的错误由状态字段承载)。
|
|
9
|
+
*/
|
|
10
|
+
export declare function syncByScope(engine: OrchestratorInternals, scope: string): Promise<void>;
|
|
6
11
|
/** 读取一次运行配置;整体失败只落 state.error,绝不 throw(start/reload 均可重试)。 */
|
|
7
12
|
export declare function load(engine: OrchestratorInternals): Promise<ReturnType<OrchestratorInternals['state']>>;
|
|
8
13
|
/** 密码登录 → 写 dsh credentials 存储 → 立即重新读取;失败抛(code 由 UI 展示)。 */
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import z from '@deepseek-ai/schemastery';
|
|
2
|
+
import { SEMI2_SETTINGS_ENTRY } from '../contract.js';
|
|
2
3
|
import type { OwnedFacts } from '../domains/types.js';
|
|
3
4
|
import type { WorkspaceEntry } from '../hub/workspace-book.js';
|
|
4
5
|
import type { SettingsLike } from './ports.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}>>;
|
|
20
|
-
/** 一个命名空间的当前有效段:官方描述符的 `value` 是不透明值,本插件只认对象段,其余按空段处理。 */
|
|
21
|
-
export declare function sectionValue(settings: SettingsLike, ns: string): Record<string, unknown>;
|
|
6
|
+
export { SEMI2_SETTINGS_ENTRY };
|
|
7
|
+
/**
|
|
8
|
+
* 归属表字段:预设注入的路由与密钥引用。
|
|
9
|
+
* 「上次注入的条目」与「用户自己写的同名条目」无法从名字分辨,这份账本是唯一依据。
|
|
10
|
+
*/
|
|
11
|
+
export declare const OWNED_FIELDS: Record<string, z>;
|
|
12
|
+
/** 工作区 → git 项目映射的字段:本地事实(换台机器要重解析),只存目录与解析结果。 */
|
|
13
|
+
export declare const WORKSPACES_FIELDS: Record<string, z>;
|
|
14
|
+
/** 一个设置段的当前有效值:官方描述符的 `value` 是不透明值,本插件只认对象段,其余按空段处理。 */
|
|
15
|
+
export declare function sectionValue(settings: SettingsLike, ns?: string): Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* 本插件写过什么的账本;账本缺失(升级时旧设置段迁不进来、或换了台机器)时按自铸引用名认领:
|
|
18
|
+
* 认领只会多回收自己写过的东西,不会碰用户手写的段。
|
|
19
|
+
*/
|
|
22
20
|
export declare function readOwned(settings: SettingsLike): OwnedFacts;
|
|
23
21
|
/** 持久化段 → 工作区条目;形状不合的行直接丢弃,不让坏数据拖垮启动。 */
|
|
24
22
|
export declare function readWorkspaces(settings: SettingsLike): WorkspaceEntry[];
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { CredentialProvider } from '@deepseek-ai/dsh-credentials';
|
|
3
3
|
import type { AgentDefaultModelConfig } from '@deepseek-ai/dsh-agent-default-model';
|
|
4
|
-
import type {
|
|
4
|
+
import type { SettingsForms } from '@deepseek-ai/dsh-settings';
|
|
5
5
|
import type { ModelSelection } from '../hub/compile.js';
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
installSection(owner: unknown, ns: string, schema: unknown, initial: Record<string, unknown>, hooks: SettingsSectionHooks<Record<string, unknown>>): unknown;
|
|
13
|
-
};
|
|
6
|
+
/**
|
|
7
|
+
* 本插件消费的 host settings 服务面:读 / 写口径照官方 `SettingsForms`。
|
|
8
|
+
* 设置段 = Profile 插件条目 id,`describe()` 只列出「光纤 ACTIVE 且 Config 声明了 volatile 字段」的条目,
|
|
9
|
+
* 因此写与读都要先等目标条目可描述(`awaitNamespace`);`replace` / `mutate` 是可缺的降级口。
|
|
10
|
+
*/
|
|
11
|
+
export type SettingsLike = Pick<SettingsForms, 'describe' | 'update'> & Partial<Pick<SettingsForms, 'replace' | 'mutate' | 'configure'>>;
|
|
14
12
|
/**
|
|
15
13
|
* 本插件消费的 dsh agentDefaultModel 服务面(默认模型与无头角色选择)。
|
|
16
14
|
* 读口取自官方 `AgentDefaultModelConfig`;写入口径不变,档位是 hub 下发的普通字符串
|
|
@@ -22,7 +20,7 @@ export type AgentDefaultModelLike = Partial<Pick<AgentDefaultModelConfig, 'curre
|
|
|
22
20
|
export interface PortsOptions {
|
|
23
21
|
/** 等 settings 服务的上限(ms)。 */
|
|
24
22
|
settingsTimeoutMs?: number | undefined;
|
|
25
|
-
/**
|
|
23
|
+
/** 等设置段可读可写的上限(ms)。 */
|
|
26
24
|
namespaceWaitMs?: number | undefined;
|
|
27
25
|
}
|
|
28
26
|
export interface Ports {
|
|
@@ -36,15 +34,21 @@ export interface Ports {
|
|
|
36
34
|
agentDefaultModel(): AgentDefaultModelLike | undefined;
|
|
37
35
|
/** workspaceController 的即时宽松读取(缺席 = headless 面,走隐式工作区)。 */
|
|
38
36
|
hasWorkspaceController(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* 等设置段出现在 `describe()`(= 条目 ACTIVE 且声明了 volatile 字段);超时返回 false。
|
|
39
|
+
* 读路径超时按空段降级,写路径超时按 `CONFIG_APPLY_FAILED` 拒绝,都由调用方决定。
|
|
40
|
+
*/
|
|
41
|
+
awaitNamespace(settings: SettingsLike, ns: string): Promise<boolean>;
|
|
39
42
|
updateNamespace(settings: SettingsLike, ns: string, patch: object): Promise<void>;
|
|
40
43
|
/**
|
|
41
|
-
*
|
|
42
|
-
* `
|
|
43
|
-
*
|
|
44
|
-
* 所以凡是本插件全权决定的段(`llm-pi-ai` 只此一个键)都走替换。
|
|
44
|
+
* 权威写入:把该条目的用户层整体对齐到给定内容。
|
|
45
|
+
* 0.1.7 的 `replace` 是「先回到组合层再合并给定字段」,不会留下服务端已撤下的条目;
|
|
46
|
+
* 只用于**本插件全权决定的段**(`llm-pi-ai` 的 `providers`):状态段一用就会连归属表一起重置。
|
|
45
47
|
*/
|
|
46
48
|
replaceNamespace(settings: SettingsLike, ns: string, section: object): Promise<void>;
|
|
47
|
-
/**
|
|
49
|
+
/** 按路径删除本插件写过的键(合并写入删不掉;命中组合层的键会回继承该值)。 */
|
|
48
50
|
clearKeys(settings: SettingsLike, ns: string, keys: readonly string[]): Promise<void>;
|
|
51
|
+
/** 关掉该条目自动生成的设置页(状态段是展示面,不是给用户编辑的表单)。 */
|
|
52
|
+
hideSettingsPage(settings: SettingsLike, owner: Context): void;
|
|
49
53
|
}
|
|
50
54
|
export declare function createPorts(ctx: Context, warn: (message: string) => void, options?: PortsOptions): Ports;
|
|
@@ -2,7 +2,12 @@ import type { RuntimeBootFacts } from '../api/index.js';
|
|
|
2
2
|
import type { LoadRun } from '../domains/types.js';
|
|
3
3
|
import type { Semi2ConfigState } from '../hub/facts.js';
|
|
4
4
|
import type { OrchestratorInternals } from './orchestrator.js';
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* 状态 + 健康 + 工作区 tab 一次写回。
|
|
7
|
+
*
|
|
8
|
+
* 用合并写入而不是 `replace`:这一段落里还有归属表与工作区映射,`replace` 会把它们一起重置。
|
|
9
|
+
* 状态字段名是编译期常量集合,合并写入不存在「服务端撤下的条目残留」问题。
|
|
10
|
+
*/
|
|
6
11
|
export declare function publishStatus(engine: OrchestratorInternals): Promise<void>;
|
|
7
12
|
/** 整体读取失败:只落 state.error 与失败态,不注入任何配置(可重载重试)。 */
|
|
8
13
|
export declare function publishFailed(engine: OrchestratorInternals, code: string): Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { OrchestratorInternals } from './orchestrator.js';
|
|
3
|
+
/**
|
|
4
|
+
* 挂上会话订阅:dsh 的会话是事件源的(`session/created` / `session/disposed`),
|
|
5
|
+
* 本插件只旁听,不改会话行为。`sessions` 服务缺席时整块跳过。
|
|
6
|
+
* 返回订阅光纤(可 await 到就绪),测试据它确认监听已挂上。
|
|
7
|
+
*/
|
|
8
|
+
export declare function installSessionReporting(engine: OrchestratorInternals, ctx?: Context): PromiseLike<unknown>;
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
/** UI 触发重载的字段:写入任意非空值即触发(写后由状态回报复位为空,无令牌比对)。 */
|
|
4
|
-
export declare const SYNC_FIELD = "sync";
|
|
5
|
-
/** 完整状态字段顺序(基座 + 按注册表顺序的领域字段);UI 与健康字段共用命名空间。 */
|
|
1
|
+
import z from '@deepseek-ai/schemastery';
|
|
2
|
+
/** 完整状态字段顺序(基座 + 按注册表顺序的领域字段);UI 与健康字段共用这一段。 */
|
|
6
3
|
export declare const STATUS_FIELDS: readonly string[];
|
|
7
|
-
/** 健康字段 schema
|
|
4
|
+
/** 健康字段 schema 键(能力 + 领域,值是 `ok:正常` 形式的编码串;读侧拆码)。 */
|
|
8
5
|
export declare const HEALTH_FIELDS_SCHEMA_KEYS: readonly string[];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
onSyncRequest(value: string): void;
|
|
12
|
-
}
|
|
13
|
-
/** 安装三个命名空间;只在拿到 settings 服务后调用一次。 */
|
|
14
|
-
export declare function installSections(ctx: Context, settings: SettingsLike, hooks: SectionHooks): void;
|
|
15
|
-
/** 读 `semi2` 命名空间的一个字段(用户写入后、回报前的过渡值)。 */
|
|
16
|
-
export declare function readSetting(settings: SettingsLike, key: string): string;
|
|
6
|
+
/** 插件 Config 的可写字段表(并入入口的 Config schema)。 */
|
|
7
|
+
export declare const STATE_CONFIG_FIELDS: Record<string, z>;
|
|
@@ -8,7 +8,7 @@ export interface RouteOptions {
|
|
|
8
8
|
bodyLimitBytes?: number | undefined;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* 本模块消费的配置面(登录 / 登出 / 健康):由入口按运行实例直接传入。
|
|
11
|
+
* 本模块消费的配置面(登录 / 登出 / 同步 / 健康):由入口按运行实例直接传入。
|
|
12
12
|
* 不用 `ctx.get('semi2Config')`——同 fiber 在 apply 里刚 provide 的严格查找会拿到
|
|
13
13
|
* undefined(fiber 尚未 ACTIVE),路由会静默不注册(登录链路无声失效的事故根因)。
|
|
14
14
|
*/
|
|
@@ -21,11 +21,13 @@ export interface RouteRuntime {
|
|
|
21
21
|
userName: string;
|
|
22
22
|
}>;
|
|
23
23
|
logout(): Promise<void>;
|
|
24
|
+
/** 界面「同步」:`workspace:<slug>` 只同步该工作区,其余(含空串)整体重载。 */
|
|
25
|
+
sync(scope: string): Promise<void>;
|
|
24
26
|
/** 健康快照(诊断与端到端断言用;GET /semi2/health)。 */
|
|
25
27
|
health(): Record<string, unknown>;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
|
-
*
|
|
30
|
+
* 注册四条路由:依赖全部由调用方传入(webServer 来自 `inject(['webServer'])` 作用域、fence 来自
|
|
29
31
|
* `connection`)。模块内不做「依赖缺席就静默不装」的判断;注册一律走 ctx.effect 保证可回收。
|
|
30
32
|
*/
|
|
31
33
|
export declare function installRoutes(ctx: Context, webServer: WebServerRouteSink, runtime: RouteRuntime, fence: RequestFence, options?: RouteOptions): void;
|
|
@@ -5,8 +5,8 @@ import type { Context } from '@deepseek-ai/cordis';
|
|
|
5
5
|
* 陈旧值只退化为原生行为。
|
|
6
6
|
*/
|
|
7
7
|
export declare const WELCOME_NOTICE_VERSION = "2026-08-13.1";
|
|
8
|
-
/** 产品级 GUI onboarding 事实的 durable settings
|
|
9
|
-
export declare const WELCOME_NOTICE_NAMESPACE = "ui-
|
|
8
|
+
/** 产品级 GUI onboarding 事实的 durable settings 段(= Profile 条目 id)。 */
|
|
9
|
+
export declare const WELCOME_NOTICE_NAMESPACE = "ui-settings-general";
|
|
10
10
|
/** 记录已确认的欢迎声明文案版本。 */
|
|
11
11
|
export declare const WELCOME_NOTICE_ACK_FIELD = "welcomeNoticeVersion";
|
|
12
12
|
/** 本模块依赖的最小 host settings 服务面。 */
|
|
@@ -28,7 +28,7 @@ export interface SeedOptions {
|
|
|
28
28
|
}
|
|
29
29
|
export declare const SEED_INTERVAL_MS = 50;
|
|
30
30
|
export declare const SEED_ATTEMPTS = 40;
|
|
31
|
-
/** 等 "ui-
|
|
31
|
+
/** 等 "ui-settings-general" 段出现后并入当前版本号(幂等);拒绝/失败会 reject 交调用方降级,段始终未就绪返回 false。 */
|
|
32
32
|
export declare function seedWelcomeAcknowledgement(settings: SettingsLike, options?: SeedOptions): Promise<boolean>;
|
|
33
33
|
/** 在可选 `settings` 服务上 best-effort 预置:只降级。 */
|
|
34
34
|
export declare function installWelcomeAck(ctx: Context): void;
|
package/lib/web/routes.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { rejected } from './fence.js';
|
|
2
2
|
const LOGIN_PATH = '/semi2/login';
|
|
3
3
|
const LOGOUT_PATH = '/semi2/logout';
|
|
4
|
+
const SYNC_PATH = '/semi2/sync';
|
|
4
5
|
const HEALTH_PATH = '/semi2/health';
|
|
5
6
|
function send(res, status, body) {
|
|
6
7
|
const payload = JSON.stringify(body);
|
|
@@ -27,7 +28,7 @@ function text(value) {
|
|
|
27
28
|
return typeof value === 'string' ? value.trim() : '';
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
+
* 注册四条路由:依赖全部由调用方传入(webServer 来自 `inject(['webServer'])` 作用域、fence 来自
|
|
31
32
|
* `connection`)。模块内不做「依赖缺席就静默不装」的判断;注册一律走 ctx.effect 保证可回收。
|
|
32
33
|
*/
|
|
33
34
|
export function installRoutes(ctx, webServer, runtime, fence, options = {}) {
|
|
@@ -82,6 +83,29 @@ export function installRoutes(ctx, webServer, runtime, fence, options = {}) {
|
|
|
82
83
|
}
|
|
83
84
|
},
|
|
84
85
|
}));
|
|
86
|
+
ctx.effect(() => webServer.register({
|
|
87
|
+
kind: 'exact',
|
|
88
|
+
path: SYNC_PATH,
|
|
89
|
+
handler: async (req, res) => {
|
|
90
|
+
if (rejected(req, res, fence))
|
|
91
|
+
return;
|
|
92
|
+
if (req.method !== 'POST') {
|
|
93
|
+
send(res, 405, { code: 'METHOD_NOT_ALLOWED' });
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const raw = await readJson(req, maxBody);
|
|
98
|
+
const body = raw !== null && typeof raw === 'object'
|
|
99
|
+
? raw
|
|
100
|
+
: {};
|
|
101
|
+
await runtime.sync(text(body.scope));
|
|
102
|
+
send(res, 200, { ok: true });
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
send(res, 400, { code: 'SYNC_FAILED' });
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
}));
|
|
85
109
|
ctx.effect(() => webServer.register({
|
|
86
110
|
kind: 'exact',
|
|
87
111
|
path: HEALTH_PATH,
|
package/lib/web/welcome-ack.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* 陈旧值只退化为原生行为。
|
|
5
5
|
*/
|
|
6
6
|
export const WELCOME_NOTICE_VERSION = '2026-08-13.1';
|
|
7
|
-
/** 产品级 GUI onboarding 事实的 durable settings
|
|
8
|
-
export const WELCOME_NOTICE_NAMESPACE = 'ui-
|
|
7
|
+
/** 产品级 GUI onboarding 事实的 durable settings 段(= Profile 条目 id)。 */
|
|
8
|
+
export const WELCOME_NOTICE_NAMESPACE = 'ui-settings-general';
|
|
9
9
|
/** 记录已确认的欢迎声明文案版本。 */
|
|
10
10
|
export const WELCOME_NOTICE_ACK_FIELD = 'welcomeNoticeVersion';
|
|
11
11
|
export const SEED_INTERVAL_MS = 50;
|
|
@@ -13,7 +13,7 @@ export const SEED_ATTEMPTS = 40;
|
|
|
13
13
|
function defaultWait(ms) {
|
|
14
14
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
15
15
|
}
|
|
16
|
-
/** 等 "ui-
|
|
16
|
+
/** 等 "ui-settings-general" 段出现后并入当前版本号(幂等);拒绝/失败会 reject 交调用方降级,段始终未就绪返回 false。 */
|
|
17
17
|
export async function seedWelcomeAcknowledgement(settings, options = {}) {
|
|
18
18
|
const namespace = options.namespace ?? WELCOME_NOTICE_NAMESPACE;
|
|
19
19
|
const intervalMs = options.intervalMs ?? SEED_INTERVAL_MS;
|
|
@@ -44,9 +44,9 @@ export function installWelcomeAck(ctx) {
|
|
|
44
44
|
return;
|
|
45
45
|
void seedWelcomeAcknowledgement(settings).then((seeded) => {
|
|
46
46
|
if (!seeded)
|
|
47
|
-
warn(ctx, 'ui-
|
|
47
|
+
warn(ctx, 'ui-settings-general 段未就绪,跳过欢迎声明预置');
|
|
48
48
|
}).catch((error) => {
|
|
49
|
-
warn(ctx, '写入 ui-
|
|
49
|
+
warn(ctx, '写入 ui-settings-general 欢迎声明确认失败: ' + (error instanceof Error ? error.message : String(error)));
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
52
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fa-software/semi2-dsh",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14-preview.20260922151653",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Semi2 单插件:semi2-hub 配置引导 + 公共 Web 能力,并挂载 CodeGraph 官方 MCP 服务。",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -38,16 +38,18 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
42
|
-
"@deepseek-ai/dsh-agent-default-model": "^0.1.
|
|
43
|
-
"@deepseek-ai/dsh-api-workspace-controller": "^0.1.
|
|
44
|
-
"@deepseek-ai/dsh-client-connection": "^0.1.
|
|
45
|
-
"@deepseek-ai/dsh-credentials": "^0.1.
|
|
46
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.
|
|
47
|
-
"@deepseek-ai/dsh-
|
|
48
|
-
"@deepseek-ai/dsh-
|
|
49
|
-
"@deepseek-ai/dsh-
|
|
50
|
-
"@deepseek-ai/
|
|
41
|
+
"@deepseek-ai/cordis": "^4.0.3",
|
|
42
|
+
"@deepseek-ai/dsh-agent-default-model": "^0.1.7-alpha.1",
|
|
43
|
+
"@deepseek-ai/dsh-api-workspace-controller": "^0.1.7-alpha.1",
|
|
44
|
+
"@deepseek-ai/dsh-client-connection": "^0.1.7-alpha.1",
|
|
45
|
+
"@deepseek-ai/dsh-credentials": "^0.1.7-alpha.1",
|
|
46
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.7-alpha.1",
|
|
47
|
+
"@deepseek-ai/dsh-mcp-client": "^0.1.7-alpha.1",
|
|
48
|
+
"@deepseek-ai/dsh-settings": "^0.1.7-alpha.1",
|
|
49
|
+
"@deepseek-ai/dsh-session": "^0.1.7-alpha.1",
|
|
50
|
+
"@deepseek-ai/dsh-skill": "^0.1.7-alpha.1",
|
|
51
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.7-alpha.1",
|
|
52
|
+
"@deepseek-ai/schemastery": "^3.18.3"
|
|
51
53
|
},
|
|
52
54
|
"peerDependenciesMeta": {
|
|
53
55
|
"@deepseek-ai/dsh-agent-default-model": {
|
|
@@ -65,9 +67,15 @@
|
|
|
65
67
|
"@deepseek-ai/dsh-host-webserver": {
|
|
66
68
|
"optional": true
|
|
67
69
|
},
|
|
70
|
+
"@deepseek-ai/dsh-mcp-client": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
68
73
|
"@deepseek-ai/dsh-settings": {
|
|
69
74
|
"optional": true
|
|
70
75
|
},
|
|
76
|
+
"@deepseek-ai/dsh-session": {
|
|
77
|
+
"optional": true
|
|
78
|
+
},
|
|
71
79
|
"@deepseek-ai/dsh-skill": {
|
|
72
80
|
"optional": true
|
|
73
81
|
},
|