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.
Files changed (63) hide show
  1. package/LICENSE +201 -0
  2. package/README.es.md +129 -0
  3. package/README.hi.md +129 -0
  4. package/README.md +129 -0
  5. package/README.pt.md +129 -0
  6. package/README.zh.md +129 -0
  7. package/cordis.patch.yml +23 -0
  8. package/lib/client.js +5045 -0
  9. package/lib/client.js.map +1 -0
  10. package/lib/index.js +1079 -0
  11. package/lib/typert.host.js +4261 -0
  12. package/lib/types/aggregate.d.ts +92 -0
  13. package/lib/types/aggregate.d.ts.map +1 -0
  14. package/lib/types/client/McpPanelTab.d.ts +16 -0
  15. package/lib/types/client/McpPanelTab.d.ts.map +1 -0
  16. package/lib/types/client/index.d.ts +35 -0
  17. package/lib/types/client/index.d.ts.map +1 -0
  18. package/lib/types/client/locales.d.ts +90 -0
  19. package/lib/types/client/locales.d.ts.map +1 -0
  20. package/lib/types/client/present.d.ts +79 -0
  21. package/lib/types/client/present.d.ts.map +1 -0
  22. package/lib/types/client/remote.d.ts +119 -0
  23. package/lib/types/client/remote.d.ts.map +1 -0
  24. package/lib/types/client/styles.d.ts +12 -0
  25. package/lib/types/client/styles.d.ts.map +1 -0
  26. package/lib/types/command.d.ts +122 -0
  27. package/lib/types/command.d.ts.map +1 -0
  28. package/lib/types/config.d.ts +63 -0
  29. package/lib/types/config.d.ts.map +1 -0
  30. package/lib/types/grouping.d.ts +49 -0
  31. package/lib/types/grouping.d.ts.map +1 -0
  32. package/lib/types/index.d.ts +41 -0
  33. package/lib/types/index.d.ts.map +1 -0
  34. package/lib/types/probe.d.ts +67 -0
  35. package/lib/types/probe.d.ts.map +1 -0
  36. package/lib/types/sanitize.d.ts +42 -0
  37. package/lib/types/sanitize.d.ts.map +1 -0
  38. package/lib/types/service.d.ts +107 -0
  39. package/lib/types/service.d.ts.map +1 -0
  40. package/lib/types/typert.host.d.ts +110 -0
  41. package/lib/types/typert.host.d.ts.map +1 -0
  42. package/lib/types/upstream.d.ts +67 -0
  43. package/lib/types/upstream.d.ts.map +1 -0
  44. package/lib/types/wire.d.ts +342 -0
  45. package/lib/types/wire.d.ts.map +1 -0
  46. package/package.json +111 -0
  47. package/src/aggregate.ts +248 -0
  48. package/src/client/McpPanelTab.tsx +257 -0
  49. package/src/client/index.ts +87 -0
  50. package/src/client/locales.ts +92 -0
  51. package/src/client/present.ts +127 -0
  52. package/src/client/remote.ts +35 -0
  53. package/src/client/styles.ts +235 -0
  54. package/src/command.ts +387 -0
  55. package/src/config.ts +110 -0
  56. package/src/grouping.ts +109 -0
  57. package/src/index.ts +86 -0
  58. package/src/probe.ts +198 -0
  59. package/src/sanitize.ts +115 -0
  60. package/src/service.ts +279 -0
  61. package/src/typert.host.ts +25 -0
  62. package/src/upstream.ts +72 -0
  63. package/src/wire.ts +221 -0
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The hand-written Typert HOST manifest for `dsh-mcp-panel`, exported as
3
+ * `./typert` so the harness's typert-loader registers the `mcpPanel` status
4
+ * and probe invocations automatically when this plugin mounts. Same shape as
5
+ * a generator output (validated by the loader): package face, empty model and
6
+ * schemas, and the canonical invocation list shared with the client Remote
7
+ * contribution (`src/wire.ts`).
8
+ *
9
+ * @module dsh-mcp-panel/typert
10
+ */
11
+
12
+ import { MCP_PANEL_INVOCATIONS } from './wire.ts'
13
+
14
+ /** Host Typert manifest (validated by `@deepseek-ai/dsh-typert-loader`). */
15
+ export const TYPERT = Object.freeze({
16
+ package: 'dsh-mcp-panel',
17
+ face: 'host',
18
+ schemas: Object.freeze([]),
19
+ invocations: MCP_PANEL_INVOCATIONS,
20
+ model: Object.freeze({
21
+ services: Object.freeze([]),
22
+ events: Object.freeze([]),
23
+ objects: Object.freeze([]),
24
+ }),
25
+ })
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The proposed upstream observability seam of `@deepseek-ai/dsh-mcp-client`
3
+ * (see `docs/upstream-proposal.md` in the deepseek-harness repository),
4
+ * consumed here before it ships: the typed `mcp/status` Cordis event and the
5
+ * `mcpStatus` query service face.
6
+ *
7
+ * Declarations merge into `@deepseek-ai/cordis`. If upstream later ships the
8
+ * same seam, its identical declarations merge cleanly; a conflicting
9
+ * signature fails this package's compile, which is the intended tripwire.
10
+ * At runtime the seam is feature-detected: with no upstream implementation
11
+ * mounted, no events arrive and `ctx.mcpStatus` is absent, so the panel falls
12
+ * back to derived facts and reports `statusSource: 'derived'`.
13
+ *
14
+ * @module dsh-mcp-panel/upstream
15
+ */
16
+
17
+ /** Supervisor phase after one `mcp/status` transition (mirrors the proposal). */
18
+ export type McpStatusPhase = 'connecting' | 'connected' | 'waiting' | 'exhausted' | 'disposed'
19
+
20
+ /**
21
+ * App-level connection-status payload emitted on every mcp-client state
22
+ * transition. `error` carries raw same-process text; DISPLAY consumers must
23
+ * sanitize (this package's `sanitize.ts`) before rendering.
24
+ */
25
+ export interface McpStatusPayload {
26
+ /** Stable local namespace from plugin config. */
27
+ serverName: string
28
+ /** Supervisor phase after the transition. */
29
+ phase: McpStatusPhase
30
+ /** Consecutive failed attempts in the current outage (0 while connected). */
31
+ attempt: number
32
+ /** Resolved reconnect budget (`reconnect.maxAttempts`). */
33
+ maxAttempts: number
34
+ /** Scheduled backoff delay while `waiting`. */
35
+ delayMs?: number
36
+ /** Raw error text of the failed attempt or re-sync. */
37
+ error?: string
38
+ /** Tools registered after the last successful sync. */
39
+ toolCount: number
40
+ /** Epoch ms of the last successful connect; absent while down. */
41
+ connectedAt?: number
42
+ }
43
+
44
+ /** Current per-server status snapshot; the query face of `mcp/status`. */
45
+ export type McpServerStatus = McpStatusPayload
46
+
47
+ /** Structural query face of the proposed `mcpStatus` service (feature-detected). */
48
+ export interface McpStatusQuery {
49
+ /** Current status of every server this process knows. */
50
+ list(): readonly McpServerStatus[]
51
+ /** Current status of one server namespace, or `undefined`. */
52
+ get(serverName: string): McpServerStatus | undefined
53
+ }
54
+
55
+ declare module '@deepseek-ai/cordis' {
56
+ interface Events {
57
+ /**
58
+ * One MCP client supervisor state transition (the proposed upstream
59
+ * observability seam). App-level: no agent or session scope.
60
+ * @param payload - post-transition status facts.
61
+ * @mode emit
62
+ */
63
+ 'mcp/status'(payload: McpStatusPayload): void
64
+ }
65
+ interface Context {
66
+ /** The proposed upstream status query service; absent until upstream ships it. */
67
+ mcpStatus?: McpStatusQuery
68
+ }
69
+ }
70
+
71
+ /** Exact event name, exported so consumers never hardcode the literal twice. */
72
+ export const MCP_STATUS_EVENT = 'mcp/status'
package/src/wire.ts ADDED
@@ -0,0 +1,221 @@
1
+ /**
2
+ * The panel's wire vocabulary: the snapshot types served over the `mcpPanel`
3
+ * Remote namespace, their zod v4 validation schema (the strict codec both
4
+ * Typert faces carry), and the single invocation descriptor shared by the
5
+ * host `./typert` manifest and the client Remote contribution. One canonical
6
+ * source for both faces keeps the host and client codecs from ever drifting
7
+ * apart.
8
+ *
9
+ * @module dsh-mcp-panel/wire
10
+ */
11
+
12
+ import { z } from 'zod'
13
+ import type { InvocationDescriptor } from '@deepseek-ai/dsh-typert-protocol'
14
+
15
+ /** Transport recorded for one configured mcp-client row. */
16
+ export type McpTransport = 'stdio' | 'streamable-http' | 'unknown'
17
+
18
+ /** Cordis Fiber phases projected for display; `null` = no fiber observed. */
19
+ export type McpFiberPhase = 'pending' | 'loading' | 'active' | 'failed' | 'unloading' | null
20
+
21
+ /** Connection phase from the proposed upstream `mcp/status` seam, plus `unknown`. */
22
+ export type McpConnectionPhase = 'connecting' | 'connected' | 'waiting' | 'exhausted' | 'disposed' | 'unknown'
23
+
24
+ /** Provenance of the connection fields: upstream events or derived facts only. */
25
+ export type McpStatusSource = 'upstream-event' | 'derived'
26
+
27
+ /** One MCP tool's model-facing view (public name + one-line description). */
28
+ export interface McpToolView {
29
+ /** Public tool name (`mcp__<server>__<raw>` or its deterministic normalized form). */
30
+ name: string
31
+ /** Server-provided description; empty when absent. */
32
+ description: string
33
+ }
34
+
35
+ /** One MCP server's read-only status view. */
36
+ export interface McpServerView {
37
+ /** Stable namespace from plugin config. */
38
+ serverName: string
39
+ /** Loader entry id carrying the mcp-client row. */
40
+ entryId: string
41
+ /** Declared transport; `unknown` when the row is not an mcp-client row or is malformed. */
42
+ transport: McpTransport
43
+ /** Display target: the command line (stdio) or the sanitized URL (streamable-http). */
44
+ target: string
45
+ /** Effective loader disabled state (includes parent groups and `!!js` evaluation). */
46
+ enabled: boolean
47
+ /** Cordis fiber phase of the row; `null` when no fiber exists. */
48
+ fiberPhase: McpFiberPhase
49
+ /** Config-declared policy facts (reconnect budget, fail-fast, tool timeout); `null` = defaults. */
50
+ configuredNote: string | null
51
+ /** Registered tools from `ctx.tools.schemas()` under `mcp__<server>__`. */
52
+ toolCount: number
53
+ /** The model-visible tools; empty for a server with none registered. */
54
+ tools: readonly McpToolView[]
55
+ /** Connection phase; `unknown` when no upstream status was observed. */
56
+ phase: McpConnectionPhase
57
+ /** Failed attempts in the current outage (upstream); `-1` when unknown. */
58
+ attempt: number
59
+ /** Resolved reconnect budget (upstream); `-1` when unknown. */
60
+ maxAttempts: number
61
+ /** Scheduled backoff delay while `waiting`; `null` otherwise or unknown. */
62
+ delayMs: number | null
63
+ /** Reconnect attempts observed this process; `-1` when unknown. */
64
+ reconnectCount: number
65
+ /** Most recent error, sanitized for display; `null` when none or unknown. */
66
+ lastError: string | null
67
+ /** Epoch ms of the last successful connect (upstream); `null` otherwise or unknown. */
68
+ connectedAt: number | null
69
+ /** Epoch ms when this process last received an upstream status event; `null` without one. */
70
+ observedAt: number | null
71
+ /** Passive-probe reachability (`null` = probing disabled or never run). */
72
+ probeState: 'reachable' | 'unreachable' | null
73
+ /** Epoch ms of the latest passive-probe settlement; `null` without one. */
74
+ probeCheckedAt: number | null
75
+ /** Where the connection fields came from. */
76
+ statusSource: McpStatusSource
77
+ }
78
+
79
+ /** One background connectivity probe (panel-only; never model context). */
80
+ export interface McpProbeView {
81
+ /** Background-job id (`mcp-probe-N`). */
82
+ id: string
83
+ /** Server the probe targeted. */
84
+ serverName: string
85
+ /** Job lifecycle state. */
86
+ status: 'running' | 'stopping' | 'completed' | 'killed' | 'failed'
87
+ /** Epoch ms when the probe started. */
88
+ startedAt: number
89
+ /** Epoch ms when the probe settled; `null` while running. */
90
+ finishedAt: number | null
91
+ /** Sanitized one-line detail (HTTP status, latency, server info, or error). */
92
+ detail: string | null
93
+ }
94
+
95
+ /** The complete panel snapshot served by `mcpPanel/status`. */
96
+ export interface McpPanelSnapshot {
97
+ /** True when the proposed upstream `mcp/status` seam produced data this process. */
98
+ observed: boolean
99
+ /** Absolute path of the profile patch layer that disable/enable suggestions name. */
100
+ patchFile: string | null
101
+ /** Suggested panel refresh interval in ms; `0` = the tab refreshes on demand only. */
102
+ refreshIntervalMs: number
103
+ /** One row per server namespace (configured rows first, leftover namespaces last). */
104
+ servers: readonly McpServerView[]
105
+ /** Connectivity probes this process, newest first. */
106
+ probes: readonly McpProbeView[]
107
+ }
108
+
109
+ /** Strict wire schema for {@link McpPanelSnapshot} (zod v4, both Typert faces). */
110
+ export const MCP_PANEL_SNAPSHOT_SCHEMA = z.object({
111
+ observed: z.boolean(),
112
+ patchFile: z.string().nullable(),
113
+ refreshIntervalMs: z.number().int(),
114
+ servers: z.array(z.object({
115
+ serverName: z.string(),
116
+ entryId: z.string(),
117
+ transport: z.union([z.literal('stdio'), z.literal('streamable-http'), z.literal('unknown')]),
118
+ target: z.string(),
119
+ enabled: z.boolean(),
120
+ fiberPhase: z.union([z.literal('pending'), z.literal('loading'), z.literal('active'), z.literal('failed'), z.literal('unloading'), z.null()]),
121
+ configuredNote: z.string().nullable(),
122
+ toolCount: z.number().int(),
123
+ tools: z.array(z.object({
124
+ name: z.string(),
125
+ description: z.string(),
126
+ })),
127
+ phase: z.union([z.literal('connecting'), z.literal('connected'), z.literal('waiting'), z.literal('exhausted'), z.literal('disposed'), z.literal('unknown')]),
128
+ attempt: z.number().int(),
129
+ maxAttempts: z.number().int(),
130
+ delayMs: z.number().int().nullable(),
131
+ reconnectCount: z.number().int(),
132
+ lastError: z.string().nullable(),
133
+ connectedAt: z.number().int().nullable(),
134
+ observedAt: z.number().int().nullable(),
135
+ probeState: z.union([z.literal('reachable'), z.literal('unreachable'), z.null()]),
136
+ probeCheckedAt: z.number().int().nullable(),
137
+ statusSource: z.union([z.literal('upstream-event'), z.literal('derived')]),
138
+ })),
139
+ probes: z.array(z.object({
140
+ id: z.string(),
141
+ serverName: z.string(),
142
+ status: z.union([z.literal('running'), z.literal('stopping'), z.literal('completed'), z.literal('killed'), z.literal('failed')]),
143
+ startedAt: z.number().int(),
144
+ finishedAt: z.number().int().nullable(),
145
+ detail: z.string().nullable(),
146
+ })),
147
+ })
148
+
149
+ /**
150
+ * The `mcpPanel/status` invocation descriptor, shared verbatim by the host
151
+ * `TYPERT` manifest (`src/typert.host.ts`) and the client
152
+ * `TypertRemoteContribution` (`src/client/remote.ts`). Hand-written in the
153
+ * exact shape the Typert generator emits; validated by the typert loader and
154
+ * the client registry at mount time.
155
+ */
156
+ export const MCP_PANEL_STATUS_DESCRIPTOR = Object.freeze({
157
+ id: 'dsh-mcp-panel#mcpPanel/status',
158
+ service: 'mcpPanel',
159
+ namespace: 'mcpPanel',
160
+ method: 'status',
161
+ invocation: Object.freeze({ kind: 'direct' }),
162
+ parameters: Object.freeze([]),
163
+ result: Object.freeze({
164
+ mode: 'strict',
165
+ typeSymbol: 'dsh-mcp-panel/types#McpPanelSnapshot',
166
+ schema: MCP_PANEL_SNAPSHOT_SCHEMA,
167
+ }),
168
+ sourceLocation: Object.freeze({ file: 'src/wire.ts', line: 1, column: 1 }),
169
+ } as const) satisfies InvocationDescriptor
170
+
171
+ /** Result of the `mcpPanel/probe` invocation: a started panel-only probe. */
172
+ export interface ProbeStarted {
173
+ /** Background-job id (`mcp-probe-N`). */
174
+ jobId: string
175
+ /** Where the result lands: the settings tab, never model context. */
176
+ note: string
177
+ }
178
+
179
+ /** Strict wire schema for {@link ProbeStarted}. */
180
+ export const PROBE_STARTED_SCHEMA = z.object({
181
+ jobId: z.string(),
182
+ note: z.string(),
183
+ })
184
+
185
+ /**
186
+ * The `mcpPanel/probe` invocation descriptor: start a one-shot probe from the
187
+ * settings panel (same background-job mechanics as the `mcp_probe` tool).
188
+ */
189
+ export const MCP_PANEL_PROBE_DESCRIPTOR = Object.freeze({
190
+ id: 'dsh-mcp-panel#mcpPanel/probe',
191
+ service: 'mcpPanel',
192
+ namespace: 'mcpPanel',
193
+ method: 'probe',
194
+ invocation: Object.freeze({ kind: 'direct' }),
195
+ parameters: Object.freeze([Object.freeze({
196
+ name: 'serverName',
197
+ wire: 'serverName',
198
+ source: 'json',
199
+ codec: Object.freeze({
200
+ mode: 'strict',
201
+ typeSymbol: 'dsh-mcp-panel/types#ProbeRequestServerName',
202
+ schema: z.string(),
203
+ }),
204
+ } satisfies InvocationDescriptor['parameters'][number])]),
205
+ result: Object.freeze({
206
+ mode: 'strict',
207
+ typeSymbol: 'dsh-mcp-panel/types#ProbeStarted',
208
+ schema: PROBE_STARTED_SCHEMA,
209
+ }),
210
+ sourceLocation: Object.freeze({ file: 'src/wire.ts', line: 1, column: 1 }),
211
+ } as const) satisfies InvocationDescriptor
212
+
213
+ /**
214
+ * The canonical invocation list both Typert faces register — the host
215
+ * manifest and the client contribution share these exact descriptor objects,
216
+ * so the two wire codecs can never drift apart.
217
+ */
218
+ export const MCP_PANEL_INVOCATIONS = Object.freeze([
219
+ MCP_PANEL_STATUS_DESCRIPTOR,
220
+ MCP_PANEL_PROBE_DESCRIPTOR,
221
+ ])