dsh-mcp-panel 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.es.md +129 -0
- package/README.hi.md +129 -0
- package/README.md +129 -0
- package/README.pt.md +129 -0
- package/README.zh.md +129 -0
- package/cordis.patch.yml +23 -0
- package/lib/client.js +5045 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +1079 -0
- package/lib/typert.host.js +4261 -0
- package/lib/types/aggregate.d.ts +92 -0
- package/lib/types/aggregate.d.ts.map +1 -0
- package/lib/types/client/McpPanelTab.d.ts +16 -0
- package/lib/types/client/McpPanelTab.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +35 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +90 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/present.d.ts +79 -0
- package/lib/types/client/present.d.ts.map +1 -0
- package/lib/types/client/remote.d.ts +119 -0
- package/lib/types/client/remote.d.ts.map +1 -0
- package/lib/types/client/styles.d.ts +12 -0
- package/lib/types/client/styles.d.ts.map +1 -0
- package/lib/types/command.d.ts +122 -0
- package/lib/types/command.d.ts.map +1 -0
- package/lib/types/config.d.ts +63 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/grouping.d.ts +49 -0
- package/lib/types/grouping.d.ts.map +1 -0
- package/lib/types/index.d.ts +41 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/probe.d.ts +67 -0
- package/lib/types/probe.d.ts.map +1 -0
- package/lib/types/sanitize.d.ts +42 -0
- package/lib/types/sanitize.d.ts.map +1 -0
- package/lib/types/service.d.ts +107 -0
- package/lib/types/service.d.ts.map +1 -0
- package/lib/types/typert.host.d.ts +110 -0
- package/lib/types/typert.host.d.ts.map +1 -0
- package/lib/types/upstream.d.ts +67 -0
- package/lib/types/upstream.d.ts.map +1 -0
- package/lib/types/wire.d.ts +342 -0
- package/lib/types/wire.d.ts.map +1 -0
- package/package.json +111 -0
- package/src/aggregate.ts +248 -0
- package/src/client/McpPanelTab.tsx +257 -0
- package/src/client/index.ts +87 -0
- package/src/client/locales.ts +92 -0
- package/src/client/present.ts +127 -0
- package/src/client/remote.ts +35 -0
- package/src/client/styles.ts +235 -0
- package/src/command.ts +387 -0
- package/src/config.ts +110 -0
- package/src/grouping.ts +109 -0
- package/src/index.ts +86 -0
- package/src/probe.ts +198 -0
- package/src/sanitize.ts +115 -0
- package/src/service.ts +279 -0
- package/src/typert.host.ts +25 -0
- package/src/upstream.ts +72 -0
- package/src/wire.ts +221 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/** Copy dictionaries for the MCP management Settings tab. */
|
|
2
|
+
|
|
3
|
+
/** Simplified Chinese dictionary and key source of truth. */
|
|
4
|
+
export const zh = {
|
|
5
|
+
tab: 'MCP',
|
|
6
|
+
loading: '正在读取 MCP 状态…',
|
|
7
|
+
error: '暂时无法读取 MCP 状态。',
|
|
8
|
+
retry: '重试',
|
|
9
|
+
empty: '此 profile 未配置官方 MCP 服务器(@deepseek-ai/dsh-mcp-client 行)。',
|
|
10
|
+
servers: '服务器',
|
|
11
|
+
tools: '工具',
|
|
12
|
+
noTools: '未注册工具',
|
|
13
|
+
status: '状态',
|
|
14
|
+
statusUnknown: '未知',
|
|
15
|
+
statusDisabled: '已停用',
|
|
16
|
+
statusFailed: '挂载失败',
|
|
17
|
+
statusConnecting: '连接中',
|
|
18
|
+
statusConnected: '已连接',
|
|
19
|
+
statusWaiting: '重连等待',
|
|
20
|
+
statusExhausted: '重连放弃',
|
|
21
|
+
statusDisposed: '已卸载',
|
|
22
|
+
reconnects: '重连',
|
|
23
|
+
lastError: '最近错误',
|
|
24
|
+
none: '—',
|
|
25
|
+
fiber: 'Cordis fiber',
|
|
26
|
+
configured: '已配置',
|
|
27
|
+
retryIn: '重试等待',
|
|
28
|
+
attempt: '尝试',
|
|
29
|
+
lastEvent: '最后事件',
|
|
30
|
+
filterTools: '过滤工具',
|
|
31
|
+
ms: 'ms',
|
|
32
|
+
derivedNote: '连接状态/重连计数来自上游 mcp/status 事件的提议(docs/upstream-proposal.md);当前未观察到上游数据,以下连接字段为"未知",其余为配置与工具注册表事实。',
|
|
33
|
+
probes: '连通性探测',
|
|
34
|
+
probeEmpty: '暂无探测记录。用 mcp_probe 工具发起一次探测。',
|
|
35
|
+
probeRunning: '运行中',
|
|
36
|
+
probeCompleted: '完成',
|
|
37
|
+
probeFailed: '失败',
|
|
38
|
+
probeKilled: '已取消',
|
|
39
|
+
probeStopping: '取消中',
|
|
40
|
+
probeNow: '探测',
|
|
41
|
+
probeReachable: '可达',
|
|
42
|
+
probeUnreachable: '不可达',
|
|
43
|
+
probeFailedAction: '探测失败',
|
|
44
|
+
patchHint: '启停只能通过 patch 建议(/mcp <server> disable|enable)手工应用到',
|
|
45
|
+
} satisfies Record<string, string>
|
|
46
|
+
|
|
47
|
+
/** MCP panel locale key union. */
|
|
48
|
+
export type McpPanelLocaleKey = keyof typeof zh
|
|
49
|
+
|
|
50
|
+
/** English dictionary checked against the Chinese key set. */
|
|
51
|
+
export const en = {
|
|
52
|
+
tab: 'MCP',
|
|
53
|
+
loading: 'Reading MCP status…',
|
|
54
|
+
error: 'MCP status is temporarily unavailable.',
|
|
55
|
+
retry: 'Retry',
|
|
56
|
+
empty: 'This profile configures no official MCP servers (@deepseek-ai/dsh-mcp-client rows).',
|
|
57
|
+
servers: 'Servers',
|
|
58
|
+
tools: 'Tools',
|
|
59
|
+
noTools: 'No tools registered',
|
|
60
|
+
status: 'Status',
|
|
61
|
+
statusUnknown: 'Unknown',
|
|
62
|
+
statusDisabled: 'Disabled',
|
|
63
|
+
statusFailed: 'Mount failed',
|
|
64
|
+
statusConnecting: 'Connecting',
|
|
65
|
+
statusConnected: 'Connected',
|
|
66
|
+
statusWaiting: 'Reconnect waiting',
|
|
67
|
+
statusExhausted: 'Reconnect gave up',
|
|
68
|
+
statusDisposed: 'Disposed',
|
|
69
|
+
reconnects: 'Reconnects',
|
|
70
|
+
lastError: 'Last error',
|
|
71
|
+
none: '—',
|
|
72
|
+
fiber: 'Cordis fiber',
|
|
73
|
+
configured: 'Configured',
|
|
74
|
+
retryIn: 'Retry in',
|
|
75
|
+
attempt: 'Attempt',
|
|
76
|
+
lastEvent: 'Last event',
|
|
77
|
+
filterTools: 'Filter tools',
|
|
78
|
+
ms: 'ms',
|
|
79
|
+
derivedNote: 'Connection status and reconnect counts come from the proposed upstream mcp/status seam (docs/upstream-proposal.md); no upstream data was observed, so connection fields read "unknown" and the rest are config and tool-registry facts.',
|
|
80
|
+
probes: 'Connectivity probes',
|
|
81
|
+
probeEmpty: 'No probes yet. Start one with the mcp_probe tool.',
|
|
82
|
+
probeRunning: 'Running',
|
|
83
|
+
probeCompleted: 'Completed',
|
|
84
|
+
probeFailed: 'Failed',
|
|
85
|
+
probeKilled: 'Killed',
|
|
86
|
+
probeStopping: 'Stopping',
|
|
87
|
+
probeNow: 'Probe',
|
|
88
|
+
probeReachable: 'Reachable',
|
|
89
|
+
probeUnreachable: 'Unreachable',
|
|
90
|
+
probeFailedAction: 'Probe failed',
|
|
91
|
+
patchHint: 'Enable/disable is a patch suggestion only (/mcp <server> disable|enable); apply it by hand to',
|
|
92
|
+
} satisfies Record<McpPanelLocaleKey, string>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure presentation for the MCP settings tab: maps the wire snapshot onto
|
|
3
|
+
* render-ready rows and badge codes. No I/O, no clock, no random — a session
|
|
4
|
+
* replay or a test may call it any number of times and get the same result.
|
|
5
|
+
* Localization happens in the component through the locale dictionaries;
|
|
6
|
+
* this module emits stable codes only.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-mcp-panel/client/present
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { McpPanelSnapshot, McpServerView, McpProbeView } from '../wire.ts'
|
|
12
|
+
|
|
13
|
+
/** Badge tones the stylesheet understands. */
|
|
14
|
+
export type BadgeTone = 'ok' | 'warn' | 'error' | 'muted'
|
|
15
|
+
|
|
16
|
+
/** Render-ready server row plus derived badge facts. */
|
|
17
|
+
export interface PresentedServerRow {
|
|
18
|
+
/** The wire server view, unchanged. */
|
|
19
|
+
readonly view: McpServerView
|
|
20
|
+
/** Badge tone for the connection state. */
|
|
21
|
+
readonly tone: BadgeTone
|
|
22
|
+
/** Badge code: `disabled` | `failed` | a connection phase | `unknown`. */
|
|
23
|
+
readonly badge: 'disabled' | 'failed' | 'connecting' | 'connected' | 'waiting' | 'exhausted' | 'disposed' | 'unknown'
|
|
24
|
+
/** Whether the row shows an error badge (sanitized `lastError` present). */
|
|
25
|
+
readonly hasError: boolean
|
|
26
|
+
/** Display form of the reconnect count (`-1` → null = dash). */
|
|
27
|
+
readonly reconnects: number | null
|
|
28
|
+
/** Whole seconds since the last upstream event; `null` = never observed. */
|
|
29
|
+
readonly ageSeconds: number | null
|
|
30
|
+
/** Whether the attempt/maxAttempts pair is displayable (either is known). */
|
|
31
|
+
readonly hasAttemptBudget: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Render-ready probe row. */
|
|
35
|
+
export interface PresentedProbeRow {
|
|
36
|
+
/** The wire probe view, unchanged. */
|
|
37
|
+
readonly view: McpProbeView
|
|
38
|
+
/** Badge tone for the probe state. */
|
|
39
|
+
readonly tone: BadgeTone
|
|
40
|
+
/** Badge code for the probe state. */
|
|
41
|
+
readonly badge: 'running' | 'completed' | 'failed' | 'killed' | 'stopping'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** The complete render-ready tab model. */
|
|
45
|
+
export interface PresentedMcpPanel {
|
|
46
|
+
/** Servers in snapshot order. */
|
|
47
|
+
readonly servers: readonly PresentedServerRow[]
|
|
48
|
+
/** Probes in snapshot order (newest first). */
|
|
49
|
+
readonly probes: readonly PresentedProbeRow[]
|
|
50
|
+
/** Whether the snapshot carries any server rows. */
|
|
51
|
+
readonly empty: boolean
|
|
52
|
+
/** Whether connection fields came from upstream or are derived. */
|
|
53
|
+
readonly observed: boolean
|
|
54
|
+
/** Absolute profile patch-layer path for the hint line, or null. */
|
|
55
|
+
readonly patchFile: string | null
|
|
56
|
+
/** Suggested refresh interval in ms (`0` = on demand only). */
|
|
57
|
+
readonly refreshIntervalMs: number
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Derive the connection badge for one server row. Order matters: the entry
|
|
62
|
+
* being disabled or its fiber failed is a configuration fact that beats the
|
|
63
|
+
* (derived or upstream) connection phase.
|
|
64
|
+
*
|
|
65
|
+
* @param view - the assembled server view.
|
|
66
|
+
* @returns the badge code and tone.
|
|
67
|
+
*/
|
|
68
|
+
export function connectionBadge(view: McpServerView): { badge: PresentedServerRow['badge']; tone: BadgeTone } {
|
|
69
|
+
// A leftover namespace (foreign mcp__ tools, no loader row) is unconfigured,
|
|
70
|
+
// not disabled: its config facts do not exist, so it reads "unknown".
|
|
71
|
+
if (view.entryId === '') return { badge: 'unknown', tone: 'muted' }
|
|
72
|
+
if (!view.enabled) return { badge: 'disabled', tone: 'muted' }
|
|
73
|
+
if (view.fiberPhase === 'failed') return { badge: 'failed', tone: 'error' }
|
|
74
|
+
switch (view.phase) {
|
|
75
|
+
case 'connected': return { badge: 'connected', tone: 'ok' }
|
|
76
|
+
case 'connecting':
|
|
77
|
+
case 'waiting': return { badge: view.phase, tone: 'warn' }
|
|
78
|
+
case 'exhausted': return { badge: 'exhausted', tone: 'error' }
|
|
79
|
+
case 'disposed': return { badge: 'disposed', tone: 'muted' }
|
|
80
|
+
default: return { badge: 'unknown', tone: 'muted' }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Badge for one probe state. */
|
|
85
|
+
export function probeBadge(status: McpProbeView['status']): { badge: PresentedProbeRow['badge']; tone: BadgeTone } {
|
|
86
|
+
switch (status) {
|
|
87
|
+
case 'completed': return { badge: 'completed', tone: 'ok' }
|
|
88
|
+
case 'running': return { badge: 'running', tone: 'warn' }
|
|
89
|
+
case 'stopping': return { badge: 'stopping', tone: 'warn' }
|
|
90
|
+
case 'failed': return { badge: 'failed', tone: 'error' }
|
|
91
|
+
case 'killed': return { badge: 'killed', tone: 'muted' }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Project the wire snapshot onto render-ready rows.
|
|
97
|
+
*
|
|
98
|
+
* @param snapshot - the `mcpPanel/status` value.
|
|
99
|
+
* @param now - epoch ms anchor for age computations (keeps the fold pure).
|
|
100
|
+
* @returns the tab model.
|
|
101
|
+
*/
|
|
102
|
+
export function presentMcpPanel(snapshot: McpPanelSnapshot, now = Date.now()): PresentedMcpPanel {
|
|
103
|
+
const servers = snapshot.servers.map((view): PresentedServerRow => {
|
|
104
|
+
const { badge, tone } = connectionBadge(view)
|
|
105
|
+
return {
|
|
106
|
+
view,
|
|
107
|
+
badge,
|
|
108
|
+
tone,
|
|
109
|
+
hasError: view.lastError !== null && view.lastError !== '',
|
|
110
|
+
reconnects: view.reconnectCount < 0 ? null : view.reconnectCount,
|
|
111
|
+
ageSeconds: view.observedAt === null ? null : Math.max(0, Math.floor((now - view.observedAt) / 1000)),
|
|
112
|
+
hasAttemptBudget: view.attempt >= 0 || view.maxAttempts > 0,
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
const probes = snapshot.probes.map((view): PresentedProbeRow => {
|
|
116
|
+
const { badge, tone } = probeBadge(view.status)
|
|
117
|
+
return { view, badge, tone }
|
|
118
|
+
})
|
|
119
|
+
return {
|
|
120
|
+
servers,
|
|
121
|
+
probes,
|
|
122
|
+
empty: snapshot.servers.length === 0,
|
|
123
|
+
observed: snapshot.observed,
|
|
124
|
+
patchFile: snapshot.patchFile,
|
|
125
|
+
refreshIntervalMs: snapshot.refreshIntervalMs,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The client-side Remote face of the `mcpPanel` namespace: the hand-written
|
|
3
|
+
* `TypertRemoteContribution` mounted through `ctx.remote.$mount`, plus the
|
|
4
|
+
* declaration merging that types `ctx.remote.mcpPanel`. The descriptor list
|
|
5
|
+
* is shared with the host `./typert` manifest (`../wire.ts`), so the two
|
|
6
|
+
* faces can never drift.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-mcp-panel/client/remote
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { RemoteResult, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'
|
|
12
|
+
import { MCP_PANEL_INVOCATIONS } from '../wire.ts'
|
|
13
|
+
import type { McpPanelSnapshot, ProbeStarted } from '../wire.ts'
|
|
14
|
+
|
|
15
|
+
declare module '@deepseek-ai/dsh-typert-protocol' {
|
|
16
|
+
interface TypertRemoteNamespace$mcpPanel {
|
|
17
|
+
/** Read the current read-only MCP snapshot. */
|
|
18
|
+
status: () => Promise<RemoteResult<McpPanelSnapshot>>
|
|
19
|
+
/** Start a one-shot connectivity probe of one streamable-http server. */
|
|
20
|
+
probe: (serverName: string) => Promise<RemoteResult<ProbeStarted>>
|
|
21
|
+
}
|
|
22
|
+
interface TypertRemoteMap {
|
|
23
|
+
'mcpPanel/status': () => Promise<RemoteResult<McpPanelSnapshot>>
|
|
24
|
+
'mcpPanel/probe': (serverName: string) => Promise<RemoteResult<ProbeStarted>>
|
|
25
|
+
}
|
|
26
|
+
interface TypertRemoteNamespaceMap {
|
|
27
|
+
mcpPanel: TypertRemoteNamespace$mcpPanel
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The client Remote contribution for the `mcpPanel` namespace. */
|
|
32
|
+
export const MCP_PANEL_REMOTE = Object.freeze({
|
|
33
|
+
package: 'dsh-mcp-panel',
|
|
34
|
+
descriptors: MCP_PANEL_INVOCATIONS,
|
|
35
|
+
} satisfies TypertRemoteContribution)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoped stylesheet for the MCP tab. Standalone client bundles cannot use the
|
|
3
|
+
* in-repo CSS-module pipeline, so the sheet ships as a string and is
|
|
4
|
+
* installed effect-scoped into a `<style data-dsh-mcp-panel>` element.
|
|
5
|
+
* Every selector is scoped under `[data-dsh-mcp-panel]` and uses theme
|
|
6
|
+
* design tokens only, so it follows both color schemes.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-mcp-panel/client/styles
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** One `<style>` installation; returns the exact disposer that removes it. */
|
|
12
|
+
export function installPanelStyles(): () => void {
|
|
13
|
+
const existing = document.querySelector('style[data-dsh-mcp-panel]')
|
|
14
|
+
if (existing !== null) return () => {}
|
|
15
|
+
const element = document.createElement('style')
|
|
16
|
+
element.dataset.dshMcpPanel = ''
|
|
17
|
+
element.textContent = PANEL_CSS
|
|
18
|
+
document.head.append(element)
|
|
19
|
+
return () => { element.remove() }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The panel stylesheet, scoped and token-driven. */
|
|
23
|
+
const PANEL_CSS = `
|
|
24
|
+
[data-dsh-mcp-panel] .dmcp-section {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
gap: 12px;
|
|
28
|
+
min-width: 0;
|
|
29
|
+
}
|
|
30
|
+
[data-dsh-mcp-panel] .dmcp-status {
|
|
31
|
+
color: var(--dsw-alias-label-secondary);
|
|
32
|
+
margin: 0;
|
|
33
|
+
}
|
|
34
|
+
[data-dsh-mcp-panel] .dmcp-failure {
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
gap: 8px;
|
|
38
|
+
align-items: flex-start;
|
|
39
|
+
}
|
|
40
|
+
[data-dsh-mcp-panel] .dmcp-failure button {
|
|
41
|
+
font: inherit;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
}
|
|
44
|
+
[data-dsh-mcp-panel] .dmcp-panel {
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
gap: 12px;
|
|
48
|
+
min-width: 0;
|
|
49
|
+
}
|
|
50
|
+
[data-dsh-mcp-panel] .dmcp-heading {
|
|
51
|
+
margin: 4px 0 0;
|
|
52
|
+
font-size: 1em;
|
|
53
|
+
color: var(--dsw-alias-label-primary);
|
|
54
|
+
}
|
|
55
|
+
[data-dsh-mcp-panel] .dmcp-cards {
|
|
56
|
+
list-style: none;
|
|
57
|
+
margin: 0;
|
|
58
|
+
padding: 0;
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
gap: 8px;
|
|
62
|
+
}
|
|
63
|
+
[data-dsh-mcp-panel] .dmcp-card {
|
|
64
|
+
border: 1px solid var(--dsw-alias-border-l3);
|
|
65
|
+
border-radius: 6px;
|
|
66
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
}
|
|
69
|
+
[data-dsh-mcp-panel] .dmcp-card-content {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: space-between;
|
|
73
|
+
gap: 8px;
|
|
74
|
+
width: 100%;
|
|
75
|
+
font: inherit;
|
|
76
|
+
text-align: left;
|
|
77
|
+
background: none;
|
|
78
|
+
border: 0;
|
|
79
|
+
color: var(--dsw-alias-label-primary);
|
|
80
|
+
padding: 10px 12px;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
}
|
|
83
|
+
[data-dsh-mcp-panel] .dmcp-card-content:focus-visible {
|
|
84
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
85
|
+
outline-offset: -2px;
|
|
86
|
+
}
|
|
87
|
+
[data-dsh-mcp-panel] .dmcp-tool-filter {
|
|
88
|
+
font: inherit;
|
|
89
|
+
color: var(--dsw-alias-label-primary);
|
|
90
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
91
|
+
border: 1px solid var(--dsw-alias-border-l3);
|
|
92
|
+
border-radius: 4px;
|
|
93
|
+
padding: 4px 8px;
|
|
94
|
+
}
|
|
95
|
+
[data-dsh-mcp-panel] .dmcp-probe-now {
|
|
96
|
+
align-self: flex-start;
|
|
97
|
+
font: inherit;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
color: var(--dsw-alias-label-primary);
|
|
100
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
101
|
+
border: 1px solid var(--dsw-alias-border-l3);
|
|
102
|
+
border-radius: 4px;
|
|
103
|
+
padding: 4px 10px;
|
|
104
|
+
}
|
|
105
|
+
[data-dsh-mcp-panel] .dmcp-probe-now:focus-visible {
|
|
106
|
+
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
107
|
+
outline-offset: -2px;
|
|
108
|
+
}
|
|
109
|
+
[data-dsh-mcp-panel] .dmcp-probe-now:disabled {
|
|
110
|
+
opacity: 0.6;
|
|
111
|
+
cursor: default;
|
|
112
|
+
}
|
|
113
|
+
[data-dsh-mcp-panel] .dmcp-card-title {
|
|
114
|
+
min-width: 0;
|
|
115
|
+
overflow: hidden;
|
|
116
|
+
text-overflow: ellipsis;
|
|
117
|
+
white-space: nowrap;
|
|
118
|
+
}
|
|
119
|
+
[data-dsh-mcp-panel] .dmcp-card-trailing {
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
gap: 8px;
|
|
123
|
+
flex-shrink: 0;
|
|
124
|
+
}
|
|
125
|
+
[data-dsh-mcp-panel] .dmcp-tool-count {
|
|
126
|
+
color: var(--dsw-alias-label-secondary);
|
|
127
|
+
white-space: nowrap;
|
|
128
|
+
}
|
|
129
|
+
[data-dsh-mcp-panel] .dmcp-card-details {
|
|
130
|
+
border-top: 1px solid var(--dsw-alias-border-l2);
|
|
131
|
+
padding: 10px 12px;
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
gap: 8px;
|
|
135
|
+
}
|
|
136
|
+
[data-dsh-mcp-panel] .dmcp-details {
|
|
137
|
+
margin: 0;
|
|
138
|
+
display: grid;
|
|
139
|
+
grid-template-columns: max-content 1fr;
|
|
140
|
+
gap: 4px 12px;
|
|
141
|
+
}
|
|
142
|
+
[data-dsh-mcp-panel] .dmcp-details dt {
|
|
143
|
+
color: var(--dsw-alias-label-secondary);
|
|
144
|
+
}
|
|
145
|
+
[data-dsh-mcp-panel] .dmcp-details dd {
|
|
146
|
+
margin: 0;
|
|
147
|
+
overflow-wrap: anywhere;
|
|
148
|
+
min-width: 0;
|
|
149
|
+
color: var(--dsw-alias-label-primary);
|
|
150
|
+
}
|
|
151
|
+
[data-dsh-mcp-panel] .dmcp-error-text {
|
|
152
|
+
color: var(--dsw-alias-state-error-primary);
|
|
153
|
+
}
|
|
154
|
+
[data-dsh-mcp-panel] .dmcp-target {
|
|
155
|
+
display: block;
|
|
156
|
+
overflow: hidden;
|
|
157
|
+
text-overflow: ellipsis;
|
|
158
|
+
white-space: nowrap;
|
|
159
|
+
color: var(--dsw-alias-label-secondary);
|
|
160
|
+
}
|
|
161
|
+
[data-dsh-mcp-panel] .dmcp-tools {
|
|
162
|
+
list-style: none;
|
|
163
|
+
margin: 0;
|
|
164
|
+
padding: 0;
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
gap: 6px;
|
|
168
|
+
}
|
|
169
|
+
[data-dsh-mcp-panel] .dmcp-tools li {
|
|
170
|
+
display: flex;
|
|
171
|
+
flex-direction: column;
|
|
172
|
+
gap: 2px;
|
|
173
|
+
}
|
|
174
|
+
[data-dsh-mcp-panel] .dmcp-tool-description {
|
|
175
|
+
color: var(--dsw-alias-label-secondary);
|
|
176
|
+
overflow-wrap: anywhere;
|
|
177
|
+
}
|
|
178
|
+
[data-dsh-mcp-panel] .dmcp-derived-note,
|
|
179
|
+
[data-dsh-mcp-panel] .dmcp-patch-hint {
|
|
180
|
+
color: var(--dsw-alias-label-secondary);
|
|
181
|
+
margin: 0;
|
|
182
|
+
overflow-wrap: anywhere;
|
|
183
|
+
}
|
|
184
|
+
[data-dsh-mcp-panel] .dmcp-probes {
|
|
185
|
+
list-style: none;
|
|
186
|
+
margin: 0;
|
|
187
|
+
padding: 0;
|
|
188
|
+
display: flex;
|
|
189
|
+
flex-direction: column;
|
|
190
|
+
gap: 6px;
|
|
191
|
+
}
|
|
192
|
+
[data-dsh-mcp-panel] .dmcp-probe {
|
|
193
|
+
display: flex;
|
|
194
|
+
align-items: baseline;
|
|
195
|
+
gap: 8px;
|
|
196
|
+
flex-wrap: wrap;
|
|
197
|
+
}
|
|
198
|
+
[data-dsh-mcp-panel] .dmcp-probe-time {
|
|
199
|
+
color: var(--dsw-alias-label-tertiary);
|
|
200
|
+
white-space: nowrap;
|
|
201
|
+
}
|
|
202
|
+
[data-dsh-mcp-panel] .dmcp-probe-detail {
|
|
203
|
+
color: var(--dsw-alias-label-secondary);
|
|
204
|
+
overflow-wrap: anywhere;
|
|
205
|
+
flex: 1 1 100%;
|
|
206
|
+
}
|
|
207
|
+
[data-dsh-mcp-panel] .dmcp-badge {
|
|
208
|
+
display: inline-flex;
|
|
209
|
+
align-items: center;
|
|
210
|
+
gap: 5px;
|
|
211
|
+
padding: 2px 8px;
|
|
212
|
+
border-radius: 999px;
|
|
213
|
+
font-size: 0.85em;
|
|
214
|
+
white-space: nowrap;
|
|
215
|
+
border: 1px solid currentColor;
|
|
216
|
+
}
|
|
217
|
+
[data-dsh-mcp-panel] .dmcp-badge[data-tone='ok'] {
|
|
218
|
+
color: var(--dsw-alias-state-success-primary);
|
|
219
|
+
}
|
|
220
|
+
[data-dsh-mcp-panel] .dmcp-badge[data-tone='warn'] {
|
|
221
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
222
|
+
}
|
|
223
|
+
[data-dsh-mcp-panel] .dmcp-badge[data-tone='error'] {
|
|
224
|
+
color: var(--dsw-alias-state-error-primary);
|
|
225
|
+
}
|
|
226
|
+
[data-dsh-mcp-panel] .dmcp-badge[data-tone='muted'] {
|
|
227
|
+
color: var(--dsw-alias-label-tertiary);
|
|
228
|
+
}
|
|
229
|
+
[data-dsh-mcp-panel] .dmcp-dot {
|
|
230
|
+
width: 8px;
|
|
231
|
+
height: 8px;
|
|
232
|
+
border-radius: 50%;
|
|
233
|
+
background: currentColor;
|
|
234
|
+
}
|
|
235
|
+
`
|