@jingyi0605/codingns4dsh 0.1.7-rc.2 → 0.2.0-beta.1
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/LICENSE +695 -0
- package/README.en.md +23 -9
- package/README.md +23 -9
- package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +1 -1
- package/data/build/dist/bootstrap/index.d.ts +1 -1
- package/data/build/dist/client/bundle.js +1200 -170
- package/data/build/dist/client/context-breakdown-dom.d.ts +53 -0
- package/data/build/dist/client/context-breakdown-dom.js +171 -0
- package/data/build/dist/client/dsh-h5-bootstrap.js +7 -1
- package/data/build/dist/client/features/cli-adapters.js +11 -0
- package/data/build/dist/client/features/index.d.ts +1 -0
- package/data/build/dist/client/features/index.js +1 -0
- package/data/build/dist/client/features/subscription-usage-panel.d.ts +15 -0
- package/data/build/dist/client/features/subscription-usage-panel.js +117 -0
- package/data/build/dist/client/features/workspace-session-enhancement-panel.js +22 -5
- package/data/build/dist/client/features/workspace-session-enhancement.js +17 -2
- package/data/build/dist/client/git-management.js +80 -10
- package/data/build/dist/client/index.d.ts +1 -0
- package/data/build/dist/client/index.js +16 -49
- package/data/build/dist/client/locale.js +20 -2
- package/data/build/dist/client/remote-web-context.js +26 -2
- package/data/build/dist/client/settings-bridge.d.ts +20 -5
- package/data/build/dist/client/settings-bridge.js +30 -7
- package/data/build/dist/client/subscription-slot.d.ts +3 -1
- package/data/build/dist/client/subscription-slot.js +31 -6
- package/data/build/dist/client/terminal/ui.js +1 -1
- package/data/build/dist/client/terminal/xterm-view.js +1 -1
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +10 -0
- package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +22 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +5 -2
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +3 -2
- package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +2 -2
- package/data/build/dist/dsh-capabilities/host/config-forms-adapter.d.ts +22 -1
- package/data/build/dist/dsh-capabilities/host/config-forms-adapter.js +29 -3
- package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.d.ts +2 -2
- package/data/build/dist/dsh-capabilities/matrix.js +31 -1
- package/data/build/dist/dsh-capabilities/routes.d.ts +8 -1
- package/data/build/dist/dsh-capabilities/routes.js +173 -5
- package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
- package/data/build/dist/features/registry.d.ts +7 -0
- package/data/build/dist/features/registry.js +20 -2
- package/data/build/dist/host/cli-adapters/feature.js +24 -2
- package/data/build/dist/host/cli-adapters/native-team-proxy.d.ts +36 -0
- package/data/build/dist/host/cli-adapters/native-team-proxy.js +108 -0
- package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +35 -0
- package/data/build/dist/host/cli-adapters/provider-subscription.js +405 -5
- package/data/build/dist/host/cli-adapters/registry.d.ts +9 -3
- package/data/build/dist/host/cli-adapters/registry.js +30 -0
- package/data/build/dist/host/cli-adapters/session-store.d.ts +8 -2
- package/data/build/dist/host/cli-adapters/session-store.js +19 -0
- package/data/build/dist/host/features/git-management.js +41 -18
- package/data/build/dist/host/features/types.d.ts +6 -3
- package/data/build/dist/host/index-injection.d.ts +12 -5
- package/data/build/dist/host/index-injection.js +32 -11
- package/data/build/dist/host/index.js +15 -4
- package/data/build/dist/host/lan-access-dsh.d.ts +2 -2
- package/data/build/dist/host/native-session-bridge.d.ts +4 -0
- package/data/build/dist/host/native-session-bridge.js +53 -7
- package/data/build/dist/host/relay-tunnel-runtime.js +10 -1
- package/data/build/dist/host/remote-web-runtime.js +40 -17
- package/data/build/dist/host/rpc.d.ts +24 -5
- package/data/build/dist/host/rpc.js +38 -9
- package/data/build/dist/host/session-migration-repair.js +14 -0
- package/data/build/dist/host/settings.d.ts +2 -2
- package/data/build/dist/host/settings.js +11 -1
- package/data/build/dist/host/terminal/startup.d.ts +2 -2
- package/data/build/dist/shared/contracts/cli-adapter.d.ts +22 -1
- package/data/build/dist/shared/contracts/config.d.ts +21 -0
- package/data/build/dist/shared/contracts/config.js +17 -0
- package/data/build/dist/shared/contracts/errors.d.ts +2 -2
- package/data/build/dist/shared/contracts/subscription.d.ts +7 -0
- package/data/build/dist/shared/contracts/subscription.js +14 -1
- package/data/build/dist/shared/contracts/version.d.ts +4 -4
- package/data/build/dist/shared/contracts/version.js +3 -3
- package/data/build/dist/shared/index.d.ts +3 -2
- package/data/build/dist/shared/index.js +2 -1
- package/data/build/dist/transport/carrier.d.ts +11 -1
- package/data/build/dist/transport/carrier.js +77 -26
- package/data/build/dist/transport/debug.d.ts +5 -0
- package/data/build/dist/transport/debug.js +17 -2
- package/data/build/dist/transport/dsh-session.d.ts +18 -1
- package/data/build/dist/transport/dsh-session.js +48 -13
- package/data/build/dist/transport/index.d.ts +1 -1
- package/data/build/dist/transport/index.js +1 -1
- package/package.json +23 -19
- package/profile/README.md +2 -2
- package/profile/package.json +4 -3
- package/profile/version.json +3 -3
- package/version.json +3 -3
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { createElement, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { isSubscriptionUsageFresh } from '../shared/contracts/subscription.js';
|
|
3
|
+
import { DEFAULT_SUBSCRIPTION_USAGE_SETTINGS } from '../shared/contracts/config.js';
|
|
2
4
|
import { callCliRpc } from './cli-catalog.js';
|
|
3
5
|
import { providerIconUrl } from './provider-icons.js';
|
|
6
|
+
import { subscribeSessionAdapters } from './session-adapter-cache.js';
|
|
4
7
|
import { dshPopupSurfaceStyle, dshThemeColor } from './theme.js';
|
|
5
8
|
const SUBSCRIPTION_STYLE_ID = 'codingns4dsh-subscription-responsive-style';
|
|
9
|
+
/**
|
|
10
|
+
* 进程内用量结果缓存:同一适配器/提供商在刷新间隔内直接复用上次结果,
|
|
11
|
+
* 避免每次进入会话或切回同一 Agent 都请求上游;null 结果不缓存,便于刚登录后立刻重试。
|
|
12
|
+
*/
|
|
13
|
+
const subscriptionUsageCache = new Map();
|
|
6
14
|
/** 移动端订阅入口只保留图标,完整数据仍可在点击后的弹层中查看。 */
|
|
7
15
|
function installSubscriptionStyles() {
|
|
8
16
|
if (typeof document === 'undefined' || document.querySelector(`style[data-plugin-css="${SUBSCRIPTION_STYLE_ID}"]`) !== null)
|
|
@@ -14,14 +22,14 @@ function installSubscriptionStyles() {
|
|
|
14
22
|
document.head.appendChild(style);
|
|
15
23
|
}
|
|
16
24
|
/** 在 DSH 原生步骤统计左侧显示当前 Agent 的订阅余量。 */
|
|
17
|
-
export function registerSubscriptionSlot(slots, rpc) {
|
|
25
|
+
export function registerSubscriptionSlot(slots, rpc, getRefreshIntervalMins) {
|
|
18
26
|
installSubscriptionStyles();
|
|
19
27
|
return slots.inject('conversation.composer.dock', () => slots.register({
|
|
20
28
|
name: 'conversation.composer.dock',
|
|
21
29
|
id: 'codingns4dsh-subscription',
|
|
22
30
|
order: -20,
|
|
23
31
|
label: 'Agent 订阅余量',
|
|
24
|
-
inject: (sessionId) => ({ rpc, sessionId }),
|
|
32
|
+
inject: (sessionId) => ({ rpc, sessionId, ...(getRefreshIntervalMins === undefined ? {} : { getRefreshIntervalMins }) }),
|
|
25
33
|
}, CommandCodeSubscriptionSlot));
|
|
26
34
|
}
|
|
27
35
|
function CommandCodeSubscriptionSlot(props) {
|
|
@@ -34,6 +42,10 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
34
42
|
const [clock, setClock] = useState(() => Date.now());
|
|
35
43
|
const rootRef = useRef(null);
|
|
36
44
|
const modelSelectionRevision = props.useSession?.((value) => JSON.stringify(value.modelSelection));
|
|
45
|
+
// 切换 Agent 可能只改变 Host 侧会话配置,DSH 会话快照不一定会更新;订阅适配器
|
|
46
|
+
// 缓存的变更才能真正触发重新查询,否则底部会一直显示上一个 Agent 的订阅数据。
|
|
47
|
+
const [adapterRevision, bumpAdapterRevision] = useState(0);
|
|
48
|
+
useEffect(() => subscribeSessionAdapters(() => { bumpAdapterRevision((value) => value + 1); }), []);
|
|
37
49
|
useEffect(() => {
|
|
38
50
|
const sessionId = props.sessionId?.trim();
|
|
39
51
|
if (!sessionId) {
|
|
@@ -69,10 +81,20 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
69
81
|
setAdapterId(adapterId);
|
|
70
82
|
setProviderId(selection.providerId ?? null);
|
|
71
83
|
}
|
|
84
|
+
const intervalMins = props.getRefreshIntervalMins?.() ?? DEFAULT_SUBSCRIPTION_USAGE_SETTINGS.refreshIntervalMins;
|
|
85
|
+
const cacheKey = `${adapterId}|${selection.providerId ?? ''}`;
|
|
86
|
+
const cached = subscriptionUsageCache.get(cacheKey);
|
|
87
|
+
if (cached !== undefined && isSubscriptionUsageFresh(cached.capturedAt, Date.now(), intervalMins)) {
|
|
88
|
+
if (active)
|
|
89
|
+
setUsage(cached.usage);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
72
92
|
const next = await callCliRpc(props.rpc, 'subscription', {
|
|
73
93
|
adapterId,
|
|
74
94
|
...(selection.providerId ? { providerId: selection.providerId } : {}),
|
|
75
95
|
});
|
|
96
|
+
if (next !== null)
|
|
97
|
+
subscriptionUsageCache.set(cacheKey, { usage: next, capturedAt: Date.now() });
|
|
76
98
|
if (active)
|
|
77
99
|
setUsage(next);
|
|
78
100
|
}
|
|
@@ -88,12 +110,14 @@ function CommandCodeSubscriptionSlot(props) {
|
|
|
88
110
|
}
|
|
89
111
|
};
|
|
90
112
|
void refresh();
|
|
91
|
-
const
|
|
113
|
+
const intervalMins = props.getRefreshIntervalMins?.() ?? DEFAULT_SUBSCRIPTION_USAGE_SETTINGS.refreshIntervalMins;
|
|
114
|
+
const timer = intervalMins > 0 ? globalThis.setInterval(() => { void refresh(); }, intervalMins * 60_000) : undefined;
|
|
92
115
|
return () => {
|
|
93
116
|
active = false;
|
|
94
|
-
|
|
117
|
+
if (timer !== undefined)
|
|
118
|
+
globalThis.clearInterval(timer);
|
|
95
119
|
};
|
|
96
|
-
}, [props.rpc, props.sessionId, modelSelectionRevision]);
|
|
120
|
+
}, [props.rpc, props.sessionId, props.getRefreshIntervalMins, modelSelectionRevision, adapterRevision]);
|
|
97
121
|
useEffect(() => {
|
|
98
122
|
if (!eligible || usage === null)
|
|
99
123
|
return;
|
|
@@ -212,7 +236,7 @@ function selectDeepseekBalance(usage) {
|
|
|
212
236
|
return usage.balances.find((balance) => balance.currency.toUpperCase() === 'USD') ?? usage.balances[0] ?? null;
|
|
213
237
|
}
|
|
214
238
|
function isSubscriptionAdapter(adapterId) {
|
|
215
|
-
return adapterId === 'command-code' || adapterId === 'codex' || adapterId === 'claude-code' || adapterId === 'dsh' || adapterId === 'grok' || adapterId === 'opencode';
|
|
239
|
+
return adapterId === 'command-code' || adapterId === 'codex' || adapterId === 'claude-code' || adapterId === 'dsh' || adapterId === 'grok' || adapterId === 'kimi' || adapterId === 'opencode';
|
|
216
240
|
}
|
|
217
241
|
function isRemoteWebContext() {
|
|
218
242
|
return globalThis.__CODINGNS4DSH_REMOTE_WEB_CONTEXT__ === true;
|
|
@@ -233,6 +257,7 @@ function subscriptionProviderName(adapterId, providerId, usage) {
|
|
|
233
257
|
case 'claude-code': return 'Claude Code';
|
|
234
258
|
case 'dsh': return 'DSH';
|
|
235
259
|
case 'grok': return 'Grok';
|
|
260
|
+
case 'kimi': return 'Kimi Code';
|
|
236
261
|
case 'opencode': return 'OpenCode';
|
|
237
262
|
default: return 'Agent';
|
|
238
263
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, Fragment, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore, } from 'react';
|
|
2
|
-
import { Button,
|
|
2
|
+
import { Button, Menu, } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
3
|
import { resolveChevronDownIcon } from '../../dsh-capabilities/client/primitives-adapter.js';
|
|
4
4
|
import { CodingNsWebTerminals } from './model.js';
|
|
5
5
|
import { createTerminalSessionRecovery } from './recovery.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createElement, useEffect, useRef, useSyncExternalStore } from 'react';
|
|
2
|
-
import { Button
|
|
2
|
+
import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
3
3
|
import { FitAddon } from '@xterm/addon-fit';
|
|
4
4
|
import { Terminal } from '@xterm/xterm';
|
|
5
5
|
import xtermCss from '@xterm/xterm/css/xterm.css';
|
|
@@ -45,6 +45,16 @@ export interface DshConfigFormSettingsOptions {
|
|
|
45
45
|
/** DSH 0.1.7 后台可能持续更新同一 entry 的 Host-only 索引时使用。 */
|
|
46
46
|
readonly writeUnfenced?: DshConfigFormUnfencedWriter;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* 解析 Host 真正下发的 ConfigForm namespace。
|
|
50
|
+
*
|
|
51
|
+
* `ConfigForms.get` 对任何 entry 都会造出一份表单:Host 持久模式下它是停在
|
|
52
|
+
* `loading` 的空表单,memory 模式下才是 `unavailable`。绑定一份 Host 没有下发的
|
|
53
|
+
* 表单会让设置页永远停在未就绪状态,并把所有模块开关显示为不可操作,因此这里
|
|
54
|
+
* 只认可共享 mirror 中列出的 entry;判定不出来时返回 undefined,由调用方退回
|
|
55
|
+
* 插件自己的 Host RPC 设置边界。
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveServedConfigFormNamespace(forms: DshClientConfigForms | undefined, entryIds: readonly string[]): string | undefined;
|
|
48
58
|
/** 0.1.7 Client ConfigForm 路由适配器。 */
|
|
49
59
|
export declare function createConfigFormSettingsStore(forms: DshClientConfigForms, namespace: string, options?: DshConfigFormSettingsOptions): CodingNsSettingsStore<CodingNsSettings>;
|
|
50
60
|
//# sourceMappingURL=config-forms-adapter.d.ts.map
|
|
@@ -12,6 +12,28 @@ const UNAVAILABLE_FORM_SNAPSHOT = Object.freeze({
|
|
|
12
12
|
writable: false,
|
|
13
13
|
status: 'unavailable',
|
|
14
14
|
});
|
|
15
|
+
/**
|
|
16
|
+
* 解析 Host 真正下发的 ConfigForm namespace。
|
|
17
|
+
*
|
|
18
|
+
* `ConfigForms.get` 对任何 entry 都会造出一份表单:Host 持久模式下它是停在
|
|
19
|
+
* `loading` 的空表单,memory 模式下才是 `unavailable`。绑定一份 Host 没有下发的
|
|
20
|
+
* 表单会让设置页永远停在未就绪状态,并把所有模块开关显示为不可操作,因此这里
|
|
21
|
+
* 只认可共享 mirror 中列出的 entry;判定不出来时返回 undefined,由调用方退回
|
|
22
|
+
* 插件自己的 Host RPC 设置边界。
|
|
23
|
+
*/
|
|
24
|
+
export function resolveServedConfigFormNamespace(forms, entryIds) {
|
|
25
|
+
if (forms === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
try {
|
|
28
|
+
const namespaces = forms.describe?.().getSnapshot().view?.namespaces;
|
|
29
|
+
debugInfo('codingns4dsh: client config form namespaces', { namespaces: namespaces?.map((item) => item.ns) });
|
|
30
|
+
return entryIds.find((id) => namespaces?.some((item) => item.ns === id));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// mirror 尚未就绪或该版本没有共享描述:交给 Host RPC 边界,不猜测表单。
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
15
37
|
/** 0.1.7 Client ConfigForm 路由适配器。 */
|
|
16
38
|
export function createConfigFormSettingsStore(forms, namespace, options = {}) {
|
|
17
39
|
const form = forms.get(namespace);
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
type IconComponent =
|
|
1
|
+
import type { ComponentType } from 'react';
|
|
2
|
+
type IconComponent = ComponentType<{
|
|
3
|
+
readonly size?: number;
|
|
4
|
+
readonly className?: string;
|
|
5
|
+
}>;
|
|
3
6
|
/**
|
|
4
7
|
* 图标导出兼容层。0.1.7 可能改名为 Regular/Medium,运行时优先使用新导出,
|
|
5
8
|
* 旧导出仍作为回退;业务组件不再直接判断 DSH 版本。
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as primitives from '@deepseek-ai/dsh-client-ui-primitives';
|
|
2
|
+
const unavailableIcon = () => null;
|
|
2
3
|
/**
|
|
3
4
|
* 图标导出兼容层。0.1.7 可能改名为 Regular/Medium,运行时优先使用新导出,
|
|
4
5
|
* 旧导出仍作为回退;业务组件不再直接判断 DSH 版本。
|
|
5
6
|
*/
|
|
6
7
|
export function resolvePlusIcon() {
|
|
7
8
|
const value = primitives;
|
|
8
|
-
return value.IconPlusOutlineRegular ?? value.IconPlusOutlineMedium ??
|
|
9
|
+
return value.IconPlusOutlineRegular ?? value.IconPlusOutlineMedium ?? value.IconPlusOutline16 ?? unavailableIcon;
|
|
9
10
|
}
|
|
10
11
|
export function resolveChevronDownIcon() {
|
|
11
12
|
const value = primitives;
|
|
12
|
-
return value.IconChevronDownOutlineRegular ?? value.IconChevronDownOutlineMedium ??
|
|
13
|
+
return value.IconChevronDownOutlineRegular ?? value.IconChevronDownOutlineMedium ?? value.IconChevronDownOutline14 ?? unavailableIcon;
|
|
13
14
|
}
|
|
14
15
|
//# sourceMappingURL=primitives-adapter.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
2
1
|
import type { CodingNsSettings } from '../../shared/contracts/config.js';
|
|
2
|
+
import type { DshClientSettingsScope } from '../../client/settings-bridge.js';
|
|
3
3
|
import { type CodingNsSettingsOperation, type CodingNsSettingsSnapshot, type CodingNsSettingsStore } from '../settings-store.js';
|
|
4
4
|
/**
|
|
5
5
|
* 旧版 Client SettingsScope 到 Codingns4DSH 内部设置接口的适配器。
|
|
@@ -8,7 +8,7 @@ import { type CodingNsSettingsOperation, type CodingNsSettingsSnapshot, type Cod
|
|
|
8
8
|
* 读取快照。这里缓存上一次的快照,内容不变时不替换引用、不唤醒订阅者,避免
|
|
9
9
|
* React 反复强制渲染(React #185)。
|
|
10
10
|
*/
|
|
11
|
-
export declare function createLegacyClientSettingsStore(scope:
|
|
11
|
+
export declare function createLegacyClientSettingsStore(scope: DshClientSettingsScope<CodingNsSettings>): CodingNsSettingsStore<CodingNsSettings>;
|
|
12
12
|
export type CodingNsClientSettingsStore = CodingNsSettingsStore<CodingNsSettings>;
|
|
13
13
|
export type { CodingNsSettingsOperation, CodingNsSettingsSnapshot };
|
|
14
14
|
//# sourceMappingURL=settings-scope-adapter.d.ts.map
|
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
import type { CodingNsSettings } from '../../shared/contracts/config.js';
|
|
2
2
|
import type { CodingNsSettingsOperation, CodingNsSettingsStore } from '../settings-store.js';
|
|
3
|
+
/**
|
|
4
|
+
* Host 设置服务的跨版本最小契约。
|
|
5
|
+
*
|
|
6
|
+
* DSH 0.1.x 曾导出 `SettingsProvider`/`SettingsScope`,0.2 改为
|
|
7
|
+
* `SettingsForms`。业务模块不应直接依赖任一版本类型,这里只描述插件实际
|
|
8
|
+
* 使用的结构;旧版和新版都通过运行时探测接入。
|
|
9
|
+
*/
|
|
10
|
+
export interface DshHostSettingsProvider extends DshHostConfigSettings {
|
|
11
|
+
readonly writable?: boolean;
|
|
12
|
+
readonly documentPath?: string | undefined;
|
|
13
|
+
readonly get?: (namespace: string) => unknown;
|
|
14
|
+
}
|
|
15
|
+
/** 供 Host 业务模块使用的稳定设置作用域。 */
|
|
16
|
+
export interface DshHostSettingsScope<T> {
|
|
17
|
+
get(): T;
|
|
18
|
+
watch(listener: (next: T, previous: T) => void | Promise<void>): () => void;
|
|
19
|
+
update(patch: Partial<T> | Record<string, unknown>): Promise<void>;
|
|
20
|
+
replace(section: T): Promise<void>;
|
|
21
|
+
}
|
|
3
22
|
/** 0.1.7 Config/SettingsForms 的最小结构化边界,避免业务代码绑定 DSH 类型包。 */
|
|
4
23
|
export interface DshHostConfigSettings {
|
|
5
24
|
describe(options?: {
|
|
6
25
|
readonly redactSecrets?: boolean;
|
|
7
26
|
}): readonly DshSettingsDescriptor[];
|
|
8
|
-
mutate(namespace: string, operations: readonly CodingNsSettingsOperation[], expectedRevision?: number): Promise<void>;
|
|
27
|
+
mutate?(namespace: string, operations: readonly CodingNsSettingsOperation[], expectedRevision?: number): Promise<void>;
|
|
28
|
+
update?(namespace: string, patch: object, expectedRevision?: number): Promise<void>;
|
|
29
|
+
replace?(namespace: string, section: object, expectedRevision?: number): Promise<void>;
|
|
9
30
|
on?(event: 'settings/document-updated', listener: (namespace: string, revision: number) => void): () => void;
|
|
10
31
|
}
|
|
11
32
|
export interface DshSettingsDescriptor {
|
|
@@ -25,21 +25,47 @@ export function createConfigSettingsStore(settings, namespace) {
|
|
|
25
25
|
getSnapshot: () => current,
|
|
26
26
|
subscribe: (listener) => { listeners.add(listener); return () => listeners.delete(listener); },
|
|
27
27
|
mutate: async (operations, expectedRevision) => {
|
|
28
|
-
|
|
28
|
+
if (typeof settings.mutate === 'function') {
|
|
29
|
+
await settings.mutate(namespace, operations, expectedRevision);
|
|
30
|
+
}
|
|
31
|
+
else if (typeof settings.update === 'function' && operations.every((operation) => operation.op === 'set')) {
|
|
32
|
+
await settings.update(namespace, operationsToPatch(operations), expectedRevision);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
throw new Error('DSH SettingsForms 不支持 mutate;含 unset 的写入不能降级为 update');
|
|
36
|
+
}
|
|
29
37
|
refresh();
|
|
30
38
|
return true;
|
|
31
39
|
},
|
|
32
40
|
set: async (field, value) => {
|
|
33
|
-
|
|
41
|
+
if (typeof settings.mutate === 'function')
|
|
42
|
+
await settings.mutate(namespace, [{ op: 'set', path: [field], value }]);
|
|
43
|
+
else if (typeof settings.update === 'function')
|
|
44
|
+
await settings.update(namespace, { [field]: value });
|
|
45
|
+
else
|
|
46
|
+
throw new Error('DSH SettingsForms 不支持 mutate/update');
|
|
34
47
|
refresh();
|
|
35
48
|
return true;
|
|
36
49
|
},
|
|
37
50
|
unset: async (field) => {
|
|
38
|
-
|
|
51
|
+
if (typeof settings.mutate === 'function')
|
|
52
|
+
await settings.mutate(namespace, [{ op: 'unset', path: [field] }]);
|
|
53
|
+
else
|
|
54
|
+
throw new Error('DSH SettingsForms 不支持 mutate,无法 unset');
|
|
39
55
|
refresh();
|
|
40
56
|
return true;
|
|
41
57
|
},
|
|
42
58
|
dispose: () => { unsubscribeHost?.(); listeners.clear(); },
|
|
43
59
|
};
|
|
44
60
|
}
|
|
61
|
+
function operationsToPatch(operations) {
|
|
62
|
+
const patch = {};
|
|
63
|
+
for (const operation of operations) {
|
|
64
|
+
if (operation.path.length !== 1)
|
|
65
|
+
throw new Error('DSH update 回退只支持一级设置字段');
|
|
66
|
+
if (operation.op === 'set')
|
|
67
|
+
patch[operation.path[0]] = operation.value;
|
|
68
|
+
}
|
|
69
|
+
return patch;
|
|
70
|
+
}
|
|
45
71
|
//# sourceMappingURL=config-forms-adapter.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { SettingsScope } from '@deepseek-ai/dsh-settings';
|
|
2
1
|
import type { CodingNsSettings } from '../../shared/contracts/config.js';
|
|
2
|
+
import type { DshHostSettingsScope } from './config-forms-adapter.js';
|
|
3
3
|
import type { CodingNsSettingsOperation, CodingNsSettingsSnapshot, CodingNsSettingsStore } from '../settings-store.js';
|
|
4
4
|
/** 旧版 Host SettingsScope 到 Codingns4DSH 内部设置接口的适配器。 */
|
|
5
|
-
export declare function createLegacyHostSettingsStore<T>(scope:
|
|
5
|
+
export declare function createLegacyHostSettingsStore<T>(scope: DshHostSettingsScope<T>): CodingNsSettingsStore<T>;
|
|
6
6
|
export type CodingNsHostSettingsStore = CodingNsSettingsStore<CodingNsSettings>;
|
|
7
7
|
export type { CodingNsSettingsOperation, CodingNsSettingsSnapshot };
|
|
8
8
|
//# sourceMappingURL=settings-scope-adapter.d.ts.map
|
|
@@ -4,7 +4,6 @@ export const DSH_CAPABILITY_MATRIX = [
|
|
|
4
4
|
route('settings.store', 'config-forms', 'host', '>=0.1.7-rc.2 <=0.1.7-rc.2', 'supported', ['host/settings.ts', 'client/settings-bridge.ts']),
|
|
5
5
|
route('connection.rpc', 'legacy-rpc-handler', 'host', '>=0.1.5-rc.3 <=0.1.6', 'supported', ['host/rpc.ts']),
|
|
6
6
|
route('connection.rpc', 'peer-aware-rpc-handler', 'host', '>=0.1.7-rc.2 <=0.1.7-rc.2', 'supported', ['host/rpc.ts']),
|
|
7
|
-
route('connection.peer', 'no-peer-context', 'host', '>=0.1.5-rc.3 <=0.1.6', 'deprecated', ['host/rpc.ts'], 'connection.peer', '0.1.8-0'),
|
|
8
7
|
route('connection.peer', 'peer-scope', 'host', '>=0.1.7-rc.2 <=0.1.7-rc.2', 'supported', ['host/rpc.ts']),
|
|
9
8
|
route('ui.icon.plus', 'fixed-plus-icon', 'client', '>=0.1.5-rc.3 <=0.1.6', 'supported', ['client/terminal/xterm-view.ts']),
|
|
10
9
|
route('ui.icon.plus', 'regular-plus-icon', 'client', '>=0.1.7-rc.2 <=0.1.7-rc.2', 'supported', ['client/terminal/xterm-view.ts']),
|
|
@@ -24,6 +23,37 @@ export const DSH_CAPABILITY_MATRIX = [
|
|
|
24
23
|
route('peer-host.native-navigation', 'peer-host-native-navigation-legacy', 'client', '>=0.1.5-rc.3 <=0.1.6', 'deprecated', ['client/features/peer-host.ts']),
|
|
25
24
|
route('peer-host.native-navigation', 'peer-host-native-navigation-modern', 'client', '>=0.1.7-rc.2 <=0.1.7-rc.2', 'supported', ['client/features/peer-host.ts']),
|
|
26
25
|
route('peer-host.remote-web-context-fallback', 'peer-host-remote-web-context-fallback', 'client', '>=0.1.5-rc.3 <=0.1.7-rc.2', 'supported', ['client/features/peer-host.ts']),
|
|
26
|
+
// DSH 0.2.0 将设置、连接和 Typert 契约升级为带版本/作用域的协议;这些路由
|
|
27
|
+
// 与 0.1.x 保持并列,禁止把两个 API 世代合并成一个宽范围。
|
|
28
|
+
route('settings.store', 'settings-forms-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/settings.ts', 'host/rpc.ts']),
|
|
29
|
+
route('connection.rpc', 'connection-rpc-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/rpc.ts', 'transport/dsh-transport.ts']),
|
|
30
|
+
route('connection.peer', 'connection-peer-admission-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/rpc.ts']),
|
|
31
|
+
route('connection.attachment', 'connection-rpc-attachment-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/rpc.ts', 'transport/dsh-transport.ts']),
|
|
32
|
+
route('connection.uplink', 'connection-rpc-uplink-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/rpc.ts', 'transport/dsh-transport.ts']),
|
|
33
|
+
route('typert.remote', 'remote-context-stream-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/terminal/terminal-controller.ts', 'client/terminal/model.ts']),
|
|
34
|
+
route('typert.context', 'typert-context-registry-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['typert.host.ts', 'host/terminal/terminal-controller.ts']),
|
|
35
|
+
route('typert.stream', 'typert-remote-stream-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['typert.host.ts', 'typert.remote-client.ts']),
|
|
36
|
+
route('session.format-v4', 'session-format-v4', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/native-session-bridge.ts', 'host/session-migration-repair.ts']),
|
|
37
|
+
route('subagent.continuable', 'subagent-continuable-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/cli-adapters/session-store.ts', 'host/cli-adapters/feature.ts']),
|
|
38
|
+
route('agent-team.native', 'agent-team-native-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/cli-adapters/feature.ts', 'host/cli-adapters/native-team-proxy.ts']),
|
|
39
|
+
route('ui.icon.plus', 'regular-plus-icon-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/terminal/xterm-view.ts']),
|
|
40
|
+
route('ui.icon.chevron', 'regular-chevron-icon-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/terminal/ui.ts']),
|
|
41
|
+
route('locale.runtime', 'locale-runtime-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/locale.ts']),
|
|
42
|
+
route('theme.runtime', 'theme-runtime-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/theme.ts']),
|
|
43
|
+
route('conversation.tool-call', 'conversation-events-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/external-tool-stream.ts']),
|
|
44
|
+
route('sidebar.right', 'sidebar-right-dock-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/terminal/ui.ts']),
|
|
45
|
+
route('typert.remote', 'remote-context-stream-020-client', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/terminal/model.ts']),
|
|
46
|
+
route('typert.context', 'typert-context-registry-020-client', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['typert.remote-client.ts', 'client/terminal/model.ts']),
|
|
47
|
+
route('typert.stream', 'typert-remote-stream-020-client', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['typert.remote-client.ts', 'client/terminal/model.ts']),
|
|
48
|
+
route('client.boot-graph', 'client-web-boot-graph-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/index.ts', 'package.json']),
|
|
49
|
+
route('peer-host.native-navigation', 'peer-host-native-navigation-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/features/peer-host.ts']),
|
|
50
|
+
route('peer-host.remote-web-context-fallback', 'peer-host-remote-web-context-fallback-020', 'client', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['client/features/peer-host.ts']),
|
|
51
|
+
route('peer-host.store', 'peer-host-store-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/features/peer-host.ts']),
|
|
52
|
+
route('peer-host.handshake', 'peer-host-handshake-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/features/peer-host.ts']),
|
|
53
|
+
route('peer-host.http-proxy', 'peer-host-http-proxy-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/features/peer-host.ts']),
|
|
54
|
+
route('peer-host.ws-proxy', 'peer-host-ws-proxy-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/features/peer-host.ts']),
|
|
55
|
+
route('peer-host.aggregate', 'peer-host-aggregate-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/features/peer-host.ts']),
|
|
56
|
+
route('peer-host.relay-route', 'peer-host-relay-route-020', 'host', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', ['host/features/peer-host.ts']),
|
|
27
57
|
];
|
|
28
58
|
function route(capability, routeId, runtime, supportedDsh, status, consumers, replacement, removableAfter) {
|
|
29
59
|
return {
|
|
@@ -6,5 +6,12 @@ import type { DshCapabilityRuntime } from './types.js';
|
|
|
6
6
|
* 探测只检查结构,不读取版本字符串;版本范围由 Registry 统一处理,避免
|
|
7
7
|
* 业务模块在运行时继续堆叠 if (version >= ...)。
|
|
8
8
|
*/
|
|
9
|
-
export declare function createDshCapabilityRegistry(dshVersion: string, runtime: DshCapabilityRuntime, context: unknown): DshCapabilityRegistry;
|
|
9
|
+
export declare function createDshCapabilityRegistry(dshVersion: string, runtime: DshCapabilityRuntime, context: unknown, facts?: DshCapabilityRuntimeFacts): DshCapabilityRegistry;
|
|
10
|
+
/**
|
|
11
|
+
* 无法从 Context 探测、只能由运行时入口提供的结构事实。
|
|
12
|
+
* 图标导出属于客户端 bundle 的静态导入,由 client/index.ts 在装配时提供。
|
|
13
|
+
*/
|
|
14
|
+
export interface DshCapabilityRuntimeFacts {
|
|
15
|
+
readonly primitives?: unknown;
|
|
16
|
+
}
|
|
10
17
|
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -5,11 +5,11 @@ import { DshCapabilityRegistry } from './registry.js';
|
|
|
5
5
|
* 探测只检查结构,不读取版本字符串;版本范围由 Registry 统一处理,避免
|
|
6
6
|
* 业务模块在运行时继续堆叠 if (version >= ...)。
|
|
7
7
|
*/
|
|
8
|
-
export function createDshCapabilityRegistry(dshVersion, runtime, context) {
|
|
8
|
+
export function createDshCapabilityRegistry(dshVersion, runtime, context, facts = {}) {
|
|
9
9
|
const registry = new DshCapabilityRegistry(dshVersion, runtime);
|
|
10
|
-
const value = context;
|
|
11
10
|
const rangeLegacy = '>=0.1.5-rc.3 <=0.1.6';
|
|
12
11
|
const rangeModern = '>=0.1.7-rc.2 <=0.1.7-rc.2';
|
|
12
|
+
const range020 = '>=0.2.0-rc.1 <=0.2.0-rc.1';
|
|
13
13
|
const add = (route) => registry.register(route);
|
|
14
14
|
if (runtime === 'host') {
|
|
15
15
|
add({ id: 'settings-scope', capability: 'settings.store', supportedDsh: rangeLegacy, runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => typeof ctx.settings?.register === 'function', create: (ctx) => ctx.settings });
|
|
@@ -18,21 +18,181 @@ export function createDshCapabilityRegistry(dshVersion, runtime, context) {
|
|
|
18
18
|
add({ id: 'connection-rpc-peer-aware', capability: 'connection.rpc', supportedDsh: rangeModern, runtime, priority: 20, status: 'supported', introducedIn: '0.1.7-rc.2', detect: (ctx) => ctx.connection !== undefined, create: (ctx) => ctx.connection });
|
|
19
19
|
add({ id: 'connection-peer', capability: 'connection.peer', supportedDsh: rangeModern, runtime, priority: 20, status: 'supported', introducedIn: '0.1.7-rc.2', detect: (ctx) => ctx.connection?.peer !== undefined, create: (ctx) => ctx.connection.peer });
|
|
20
20
|
add({ id: 'remote-result', capability: 'typert.remote', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => ctx.remote !== undefined, create: (ctx) => ctx.remote });
|
|
21
|
+
addDsh020HostRoutes(add, range020);
|
|
21
22
|
addPeerHostHostRoutes(add);
|
|
22
23
|
}
|
|
23
24
|
else {
|
|
24
25
|
add({ id: 'settings-scope', capability: 'settings.store', supportedDsh: rangeLegacy, runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => typeof ctx.settingsScope?.bind === 'function', create: (ctx) => ctx.settingsScope });
|
|
25
26
|
add({ id: 'config-form', capability: 'settings.store', supportedDsh: rangeModern, runtime, priority: 20, status: 'supported', introducedIn: '0.1.7-rc.2', detect: (ctx) => typeof ctx.configForms?.get === 'function', create: (ctx) => ctx.configForms });
|
|
26
|
-
add({ id: 'icon-primitives', capability: 'ui.icon.plus', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: () =>
|
|
27
|
+
add({ id: 'icon-primitives', capability: 'ui.icon.plus', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: () => facts.primitives !== undefined, create: () => facts.primitives });
|
|
27
28
|
add({ id: 'locale-runtime', capability: 'locale.runtime', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => ctx.locale !== undefined, create: (ctx) => ctx.locale });
|
|
28
29
|
add({ id: 'theme-runtime', capability: 'theme.runtime', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => ctx.theme !== undefined, create: (ctx) => ctx.theme });
|
|
29
30
|
add({ id: 'conversation-events', capability: 'conversation.tool-call', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => ctx.uiConversation !== undefined, create: (ctx) => ctx.uiConversation });
|
|
30
31
|
add({ id: 'sidebar-right', capability: 'sidebar.right', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => ctx.sidebarRight !== undefined, create: (ctx) => ctx.sidebarRight });
|
|
31
32
|
add({ id: 'remote-result', capability: 'typert.remote', supportedDsh: '>=0.1.5-rc.3 <=0.1.7-rc.2', runtime, priority: 10, status: 'supported', introducedIn: '0.1.5-rc.3', detect: (ctx) => ctx.remote !== undefined, create: (ctx) => ctx.remote });
|
|
33
|
+
addDsh020ClientRoutes(add, range020, facts);
|
|
32
34
|
addPeerHostClientRoutes(add);
|
|
33
35
|
}
|
|
34
36
|
return registry;
|
|
35
37
|
}
|
|
38
|
+
/** DSH 0.2 Host 结构化能力。检测基于服务形状,不把版本判断散落到业务模块。 */
|
|
39
|
+
function addDsh020HostRoutes(add, supportedDsh) {
|
|
40
|
+
add({
|
|
41
|
+
id: 'settings-forms-020', capability: 'settings.store', supportedDsh, runtime: 'host', priority: 30,
|
|
42
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
43
|
+
detect: (ctx) => hasMethods(read(ctx, 'settings'), ['describe', 'mutate', 'configure']),
|
|
44
|
+
create: (ctx) => read(ctx, 'settings'),
|
|
45
|
+
});
|
|
46
|
+
add({
|
|
47
|
+
id: 'connection-rpc-020', capability: 'connection.rpc', supportedDsh, runtime: 'host', priority: 30,
|
|
48
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
49
|
+
detect: (ctx) => hasMethods(read(ctx, 'connection.rpc'), ['handle', 'intercept']) && hasMethods(read(ctx, 'connection.fetch'), ['register']),
|
|
50
|
+
create: (ctx) => read(ctx, 'connection'),
|
|
51
|
+
});
|
|
52
|
+
add({
|
|
53
|
+
id: 'connection-peer-admission-020', capability: 'connection.peer', supportedDsh, runtime: 'host', priority: 30,
|
|
54
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
55
|
+
detect: (ctx) => hasMethods(read(ctx, 'connection'), ['admit', 'requestRejection']) && read(ctx, 'connection.operator') !== undefined,
|
|
56
|
+
create: (ctx) => read(ctx, 'connection'),
|
|
57
|
+
});
|
|
58
|
+
add({
|
|
59
|
+
id: 'connection-rpc-attachment-020', capability: 'connection.attachment', supportedDsh, runtime: 'host', priority: 10,
|
|
60
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
61
|
+
detect: (ctx) => hasMethods(read(ctx, 'connection.rpc'), ['handle']) && hasMethods(read(ctx, 'connection.fetch'), ['register']),
|
|
62
|
+
create: (ctx) => read(ctx, 'connection'),
|
|
63
|
+
});
|
|
64
|
+
add({
|
|
65
|
+
id: 'connection-rpc-uplink-020', capability: 'connection.uplink', supportedDsh, runtime: 'host', priority: 10,
|
|
66
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
67
|
+
detect: (ctx) => hasMethods(read(ctx, 'connection.rpc'), ['handle']) && read(ctx, 'connection.operator') !== undefined,
|
|
68
|
+
create: (ctx) => read(ctx, 'connection'),
|
|
69
|
+
});
|
|
70
|
+
add({
|
|
71
|
+
id: 'remote-context-stream-020', capability: 'typert.remote', supportedDsh, runtime: 'host', priority: 30,
|
|
72
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
73
|
+
// 0.2 Host 用 `ctx.typert` 注册表承载 Remote 服务(TypertRemoteService);
|
|
74
|
+
// `ctx.remote` 属于浏览器装配,不会出现在 Host 组合里。
|
|
75
|
+
detect: (ctx) => read(ctx, 'typert.remotes') !== undefined && read(ctx, 'typert.local') !== undefined,
|
|
76
|
+
create: (ctx) => read(ctx, 'typert'),
|
|
77
|
+
});
|
|
78
|
+
add({
|
|
79
|
+
id: 'typert-context-registry-020', capability: 'typert.context', supportedDsh, runtime: 'host', priority: 10,
|
|
80
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
81
|
+
detect: (ctx) => hasMethods(read(ctx, 'typert.contexts'), ['getHost', 'getClient']),
|
|
82
|
+
create: (ctx) => read(ctx, 'typert.contexts'),
|
|
83
|
+
});
|
|
84
|
+
add({
|
|
85
|
+
id: 'typert-remote-stream-020', capability: 'typert.stream', supportedDsh, runtime: 'host', priority: 10,
|
|
86
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
87
|
+
// 流式端点由 Remote 注册表承载(descriptor.mode === 'stream')。
|
|
88
|
+
detect: (ctx) => hasMethods(read(ctx, 'typert.remotes'), ['register', 'list']),
|
|
89
|
+
create: (ctx) => read(ctx, 'typert.remotes'),
|
|
90
|
+
});
|
|
91
|
+
add({
|
|
92
|
+
id: 'session-format-v4', capability: 'session.format-v4', supportedDsh, runtime: 'host', priority: 10,
|
|
93
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
94
|
+
// generation 由 SessionStore 中每个会话头部的 version 决定;这里只确认 0.2
|
|
95
|
+
// 的 Store 形状,具体 generation 仍由 native-session-bridge 按会话读取。
|
|
96
|
+
detect: (ctx) => hasMethods(read(ctx, 'sessions'), ['get', 'list']),
|
|
97
|
+
create: (ctx) => read(ctx, 'sessions'),
|
|
98
|
+
});
|
|
99
|
+
add({
|
|
100
|
+
id: 'subagent-continuable-020', capability: 'subagent.continuable', supportedDsh, runtime: 'host', priority: 10,
|
|
101
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
102
|
+
// 0.2 的可续子代理是 SubagentRuntime 的公开操作 startContinuable/sendMessage。
|
|
103
|
+
detect: (ctx) => hasMethods(read(ctx, 'subagents'), ['startContinuable', 'sendMessage']),
|
|
104
|
+
create: (ctx) => read(ctx, 'subagents'),
|
|
105
|
+
});
|
|
106
|
+
add({
|
|
107
|
+
id: 'agent-team-native-020', capability: 'agent-team.native', supportedDsh, runtime: 'host', priority: 10,
|
|
108
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
109
|
+
// 原生 Team 代理同时需要 TeamService 的成员/派生操作与 Agent 注册表。
|
|
110
|
+
detect: (ctx) => hasMethods(read(ctx, 'agentTeams'), ['listMembers', 'spawnTeammate']) && read(ctx, 'agents') !== undefined,
|
|
111
|
+
create: (ctx) => read(ctx, 'agentTeams'),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/** DSH 0.2 Client 结构化能力;图标和 UI 服务允许由新旧导出共同提供。 */
|
|
115
|
+
function addDsh020ClientRoutes(add, supportedDsh, facts) {
|
|
116
|
+
add({
|
|
117
|
+
id: 'config-forms-020', capability: 'settings.store', supportedDsh, runtime: 'client', priority: 30,
|
|
118
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
119
|
+
detect: (ctx) => hasMethods(read(ctx, 'settings'), ['describe', 'update']) || hasMethods(read(ctx, 'configForms'), ['get']),
|
|
120
|
+
create: (ctx) => read(ctx, 'settings') ?? read(ctx, 'configForms'),
|
|
121
|
+
});
|
|
122
|
+
add({
|
|
123
|
+
id: 'regular-plus-icon-020', capability: 'ui.icon.plus', supportedDsh, runtime: 'client', priority: 30,
|
|
124
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
125
|
+
detect: () => hasAny(facts.primitives, ['IconPlusOutlineRegular', 'IconPlusOutlineMedium']),
|
|
126
|
+
create: () => facts.primitives,
|
|
127
|
+
});
|
|
128
|
+
add({
|
|
129
|
+
id: 'regular-chevron-icon-020', capability: 'ui.icon.chevron', supportedDsh, runtime: 'client', priority: 30,
|
|
130
|
+
status: 'supported', introducedIn: '0.2.0-rc.1',
|
|
131
|
+
detect: () => hasAny(facts.primitives, ['IconChevronDownOutlineRegular', 'IconChevronDownOutlineMedium']),
|
|
132
|
+
create: () => facts.primitives,
|
|
133
|
+
});
|
|
134
|
+
add({ id: 'locale-runtime-020', capability: 'locale.runtime', supportedDsh, runtime: 'client', priority: 30, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => read(ctx, 'locale') !== undefined, create: (ctx) => read(ctx, 'locale') });
|
|
135
|
+
add({ id: 'theme-runtime-020', capability: 'theme.runtime', supportedDsh, runtime: 'client', priority: 30, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => read(ctx, 'theme') !== undefined, create: (ctx) => read(ctx, 'theme') });
|
|
136
|
+
add({ id: 'conversation-events-020', capability: 'conversation.tool-call', supportedDsh, runtime: 'client', priority: 30, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => read(ctx, 'uiConversation') !== undefined, create: (ctx) => read(ctx, 'uiConversation') });
|
|
137
|
+
add({ id: 'sidebar-right-dock-020', capability: 'sidebar.right', supportedDsh, runtime: 'client', priority: 30, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => read(ctx, 'sidebarRight') !== undefined || read(ctx, 'sidebarRightTabs') !== undefined, create: (ctx) => read(ctx, 'sidebarRight') ?? read(ctx, 'sidebarRightTabs') });
|
|
138
|
+
add({ id: 'remote-context-stream-020-client', capability: 'typert.remote', supportedDsh, runtime: 'client', priority: 30, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => hasMethods(read(ctx, 'remote'), ['$mount']), create: (ctx) => read(ctx, 'remote') });
|
|
139
|
+
add({ id: 'typert-context-registry-020-client', capability: 'typert.context', supportedDsh, runtime: 'client', priority: 10, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => hasMethods(read(ctx, 'typert.contexts'), ['getHost', 'getClient']), create: (ctx) => read(ctx, 'typert.contexts') });
|
|
140
|
+
add({ id: 'typert-remote-stream-020-client', capability: 'typert.stream', supportedDsh, runtime: 'client', priority: 10, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => hasMethods(read(ctx, 'remote'), ['$mount', '$stream']), create: (ctx) => read(ctx, 'remote') });
|
|
141
|
+
add({ id: 'client-web-boot-graph-020', capability: 'client.boot-graph', supportedDsh, runtime: 'client', priority: 10, status: 'supported', introducedIn: '0.2.0-rc.1', detect: (ctx) => read(ctx, 'modules.version') === 'client', create: (ctx) => read(ctx, 'modules') });
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 读取探测上下文里的服务或结构事实。
|
|
145
|
+
*
|
|
146
|
+
* Cordis 的 Context 只在调用方 fiber 的 inject 链(或祖先 fiber 提供的服务)里
|
|
147
|
+
* 解析属性;直接读未注入的服务会抛 `cannot get property "x" without inject`,
|
|
148
|
+
* 把 `a || b` 形式的探测短路成失败。因此这里统一先走 `ctx.get(...)`(Cordis 提供
|
|
149
|
+
* 的免 inject 读取),再回退到普通属性读取,让探测只依据服务形状,不受消费方
|
|
150
|
+
* inject 列表影响。
|
|
151
|
+
*/
|
|
152
|
+
function read(context, path) {
|
|
153
|
+
const [head, ...rest] = path.split('.');
|
|
154
|
+
if (head === undefined)
|
|
155
|
+
return undefined;
|
|
156
|
+
let value = readKey(context, head);
|
|
157
|
+
for (const key of rest) {
|
|
158
|
+
value = readProperty(value, key);
|
|
159
|
+
}
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
/** 读取上下文上的服务(优先 `ctx.get`)或直接挂在上下文上的事实对象。 */
|
|
163
|
+
function readKey(context, key) {
|
|
164
|
+
if (typeof context !== 'object' || context === null)
|
|
165
|
+
return undefined;
|
|
166
|
+
const getter = readProperty(context, 'get');
|
|
167
|
+
if (typeof getter === 'function') {
|
|
168
|
+
try {
|
|
169
|
+
const value = getter.call(context, key);
|
|
170
|
+
if (value !== undefined)
|
|
171
|
+
return value;
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Cordis 读取失败按缺失处理,继续尝试普通属性。
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return readProperty(context, key);
|
|
178
|
+
}
|
|
179
|
+
/** 读取对象属性;Cordis 代理对未注入的服务会抛错,统一按缺失处理。 */
|
|
180
|
+
function readProperty(target, key) {
|
|
181
|
+
if (typeof target !== 'object' || target === null)
|
|
182
|
+
return undefined;
|
|
183
|
+
try {
|
|
184
|
+
return Reflect.get(target, key);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function hasMethods(value, methods) {
|
|
191
|
+
return typeof value === 'object' && value !== null && methods.every((method) => typeof Reflect.get(value, method) === 'function');
|
|
192
|
+
}
|
|
193
|
+
function hasAny(value, keys) {
|
|
194
|
+
return typeof value === 'object' && value !== null && keys.some((key) => Reflect.get(value, key) !== undefined);
|
|
195
|
+
}
|
|
36
196
|
/** PeerHost Host 能力只接受显式注入的适配器,避免把普通 DSH 服务误报为已实现。 */
|
|
37
197
|
function addPeerHostHostRoutes(add) {
|
|
38
198
|
addPeerHostRoute(add, 'peer-host.store', 'peer-host-store', 'peerHostStore');
|
|
@@ -41,12 +201,20 @@ function addPeerHostHostRoutes(add) {
|
|
|
41
201
|
addPeerHostRoute(add, 'peer-host.ws-proxy', 'peer-host-ws-proxy', 'peerHostWsProxy');
|
|
42
202
|
addPeerHostRoute(add, 'peer-host.aggregate', 'peer-host-aggregate', 'peerHostAggregate');
|
|
43
203
|
addPeerHostRoute(add, 'peer-host.relay-route', 'peer-host-relay-route', 'peerHostRelayRoute');
|
|
204
|
+
addPeerHostRoute(add, 'peer-host.store', 'peer-host-store-020', 'peerHostStore', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
205
|
+
addPeerHostRoute(add, 'peer-host.handshake', 'peer-host-handshake-020', 'peerHostHandshake', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
206
|
+
addPeerHostRoute(add, 'peer-host.http-proxy', 'peer-host-http-proxy-020', 'peerHostHttpProxy', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
207
|
+
addPeerHostRoute(add, 'peer-host.ws-proxy', 'peer-host-ws-proxy-020', 'peerHostWsProxy', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
208
|
+
addPeerHostRoute(add, 'peer-host.aggregate', 'peer-host-aggregate-020', 'peerHostAggregate', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
209
|
+
addPeerHostRoute(add, 'peer-host.relay-route', 'peer-host-relay-route-020', 'peerHostRelayRoute', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
44
210
|
}
|
|
45
211
|
/** PeerHost Client 导航能力由独立 adapter 注入;未注入时由 Feature 诊断降级。 */
|
|
46
212
|
function addPeerHostClientRoutes(add) {
|
|
47
213
|
addPeerHostRoute(add, 'peer-host.native-navigation', 'peer-host-native-navigation-legacy', 'peerHostNativeNavigation', '>=0.1.5-rc.3 <=0.1.6', 'deprecated');
|
|
48
214
|
addPeerHostRoute(add, 'peer-host.native-navigation', 'peer-host-native-navigation-modern', 'peerHostNativeNavigation', '>=0.1.7-rc.2 <=0.1.7-rc.2', 'supported', 20);
|
|
49
215
|
addPeerHostRoute(add, 'peer-host.remote-web-context-fallback', 'peer-host-remote-web-context-fallback', 'peerHostRemoteWebContextFallback');
|
|
216
|
+
addPeerHostRoute(add, 'peer-host.native-navigation', 'peer-host-native-navigation-020', 'peerHostNativeNavigation', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
217
|
+
addPeerHostRoute(add, 'peer-host.remote-web-context-fallback', 'peer-host-remote-web-context-fallback-020', 'peerHostRemoteWebContextFallback', '>=0.2.0-rc.1 <=0.2.0-rc.1', 'supported', 30);
|
|
50
218
|
}
|
|
51
219
|
function addPeerHostRoute(add, capability, id, field, supportedDsh = '>=0.1.5-rc.3 <=0.1.7-rc.2', status = 'supported', priority = 10) {
|
|
52
220
|
add({
|
|
@@ -62,8 +230,8 @@ function addPeerHostRoute(add, capability, id, field, supportedDsh = '>=0.1.5-rc
|
|
|
62
230
|
});
|
|
63
231
|
}
|
|
64
232
|
function readPeerHostAdapter(context, field) {
|
|
65
|
-
if (
|
|
233
|
+
if (Array.isArray(context))
|
|
66
234
|
return undefined;
|
|
67
|
-
return context
|
|
235
|
+
return readKey(context, field);
|
|
68
236
|
}
|
|
69
237
|
//# sourceMappingURL=routes.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** DSH 宿主能力的稳定标识。业务模块只依赖这些标识,不直接依赖 DSH 版本。 */
|
|
2
|
-
export type DshCapabilityId = 'settings.store' | 'connection.rpc' | 'connection.peer' | 'ui.icon.plus' | 'ui.icon.chevron' | 'locale.runtime' | 'theme.runtime' | 'conversation.tool-call' | 'sidebar.right' | 'typert.remote' | 'peer-host.store' | 'peer-host.handshake' | 'peer-host.http-proxy' | 'peer-host.ws-proxy' | 'peer-host.aggregate' | 'peer-host.relay-route' | 'peer-host.native-navigation' | 'peer-host.remote-web-context-fallback';
|
|
2
|
+
export type DshCapabilityId = 'settings.store' | 'connection.rpc' | 'connection.peer' | 'connection.attachment' | 'connection.uplink' | 'ui.icon.plus' | 'ui.icon.chevron' | 'locale.runtime' | 'theme.runtime' | 'conversation.tool-call' | 'sidebar.right' | 'typert.remote' | 'typert.context' | 'typert.stream' | 'session.format-v4' | 'subagent.continuable' | 'agent-team.native' | 'client.boot-graph' | 'peer-host.store' | 'peer-host.handshake' | 'peer-host.http-proxy' | 'peer-host.ws-proxy' | 'peer-host.aggregate' | 'peer-host.relay-route' | 'peer-host.native-navigation' | 'peer-host.remote-web-context-fallback';
|
|
3
3
|
export type DshCapabilityRuntime = 'host' | 'client';
|
|
4
4
|
export type DshCapabilityRouteStatus = 'supported' | 'deprecated';
|
|
5
5
|
export type DshCapabilityResolutionStatus = 'ready' | 'degraded' | 'unavailable';
|