dsh-agent-plugins-market 0.5.2 → 0.6.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/README.md +29 -3
- package/README.zh.md +29 -3
- package/client/client.js +1388 -204
- package/client/client.js.map +1 -1
- package/lib/application/catalog.js +537 -71
- package/lib/application/details.js +39 -12
- package/lib/catalog/archive.js +341 -0
- package/lib/catalog/git.js +85 -12
- package/lib/catalog/legacy-root-migration.js +51 -0
- package/lib/catalog/lsp-spec.js +87 -0
- package/lib/catalog/manifests.js +84 -32
- package/lib/catalog/paths.js +65 -7
- package/lib/catalog/scan-pipeline.js +50 -0
- package/lib/catalog/scan-resolvers.js +402 -0
- package/lib/catalog/source-catalog.js +22 -8
- package/lib/catalog/suite-scanner.js +5 -176
- package/lib/catalog/surfaces.js +80 -30
- package/lib/contracts/lsp-status.js +2 -0
- package/lib/contracts/market.js +8 -1
- package/lib/index.js +118 -13
- package/lib/model/state.js +14 -1
- package/lib/model/types.js +21 -2
- package/lib/routes.js +88 -6
- package/lib/runtime/commands-mounts.js +6 -2
- package/lib/runtime/hooks-mounts.js +9 -6
- package/lib/runtime/lsp-direct-config.js +44 -0
- package/lib/runtime/lsp-mounts.js +236 -0
- package/lib/runtime/lsp-status.js +96 -0
- package/lib/runtime/mcp-backend.js +60 -0
- package/lib/runtime/mcp-client/bridge.js +126 -0
- package/lib/runtime/mcp-client/config.js +42 -0
- package/lib/runtime/mcp-client/connection.js +380 -0
- package/lib/runtime/mcp-client/host-seams.js +88 -0
- package/lib/runtime/mcp-client/json-schema-subset.js +181 -0
- package/lib/runtime/mcp-client/oauth.js +379 -0
- package/lib/runtime/mcp-client/tools.js +432 -0
- package/lib/runtime/mcp-client/transport.js +103 -0
- package/lib/runtime/mcp-config.js +196 -54
- package/lib/runtime/mcp-credentials.js +20 -0
- package/lib/runtime/mcp-mounts.js +237 -27
- package/lib/runtime/mcp-overrides.js +64 -6
- package/lib/runtime/mcp-redaction.js +92 -0
- package/lib/runtime/mcp-status.js +76 -32
- package/lib/runtime/reconciler.js +35 -1
- package/lib/runtime/regions.js +56 -0
- package/lib/types/application/catalog.d.ts +191 -14
- package/lib/types/application/details.d.ts +1 -6
- package/lib/types/application/queries.d.ts +28 -1
- package/lib/types/catalog/archive.d.ts +48 -0
- package/lib/types/catalog/git.d.ts +27 -3
- package/lib/types/catalog/legacy-root-migration.d.ts +14 -0
- package/lib/types/catalog/lsp-spec.d.ts +14 -0
- package/lib/types/catalog/manifests.d.ts +16 -1
- package/lib/types/catalog/paths.d.ts +23 -2
- package/lib/types/catalog/scan-pipeline.d.ts +76 -0
- package/lib/types/catalog/scan-resolvers.d.ts +81 -0
- package/lib/types/catalog/source-catalog.d.ts +5 -0
- package/lib/types/catalog/suite-scanner.d.ts +14 -7
- package/lib/types/catalog/surfaces.d.ts +3 -3
- package/lib/types/contracts/lsp-status.d.ts +53 -0
- package/lib/types/contracts/market.d.ts +55 -1
- package/lib/types/contracts/mcp-status.d.ts +14 -2
- package/lib/types/index.d.ts +24 -8
- package/lib/types/model/types.d.ts +52 -3
- package/lib/types/runtime/lsp-direct-config.d.ts +12 -0
- package/lib/types/runtime/lsp-mounts.d.ts +89 -0
- package/lib/types/runtime/lsp-status.d.ts +30 -0
- package/lib/types/runtime/mcp-backend.d.ts +49 -0
- package/lib/types/runtime/mcp-client/bridge.d.ts +37 -0
- package/lib/types/runtime/mcp-client/config.d.ts +123 -0
- package/lib/types/runtime/mcp-client/connection.d.ts +82 -0
- package/lib/types/runtime/mcp-client/host-seams.d.ts +89 -0
- package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +58 -0
- package/lib/types/runtime/mcp-client/oauth.d.ts +121 -0
- package/lib/types/runtime/mcp-client/tools.d.ts +136 -0
- package/lib/types/runtime/mcp-client/transport.d.ts +36 -0
- package/lib/types/runtime/mcp-config.d.ts +29 -12
- package/lib/types/runtime/mcp-credentials.d.ts +9 -0
- package/lib/types/runtime/mcp-mounts.d.ts +56 -6
- package/lib/types/runtime/mcp-overrides.d.ts +23 -4
- package/lib/types/runtime/mcp-redaction.d.ts +7 -0
- package/lib/types/runtime/mcp-status.d.ts +4 -2
- package/lib/types/runtime/reconciler.d.ts +22 -4
- package/lib/types/runtime/regions.d.ts +37 -0
- package/package.json +15 -11
- package/schemas/1.0.0/mcp.schema.json +22 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Suite, SuiteDimension } from '../model/types.js';
|
|
2
|
+
import { type MarketplaceEntry } from './manifests.js';
|
|
3
|
+
import type { ScanChain, ScanContext, ScanFilter, ScanResolution, ScanResult } from './scan-pipeline.js';
|
|
4
|
+
export { repoName } from './manifests.js';
|
|
5
|
+
export { listMdFiles, discoverLspEntries, type LspEntry } from './surfaces.js';
|
|
6
|
+
export type { MarketplaceEntry } from './manifests.js';
|
|
7
|
+
export interface SuiteHint {
|
|
8
|
+
name?: string;
|
|
9
|
+
version?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
/** Inline `lspServers` declared on the marketplace entry itself (Claude Code). */
|
|
12
|
+
lspServers?: unknown;
|
|
13
|
+
}
|
|
14
|
+
/** Normalized resolution of one marketplace entry inside its checkout. */
|
|
15
|
+
export type EntryResolution = {
|
|
16
|
+
kind: 'local';
|
|
17
|
+
dir: string;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'remote';
|
|
20
|
+
url: string;
|
|
21
|
+
} | {
|
|
22
|
+
kind: 'unclaimed';
|
|
23
|
+
reason: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'rejected';
|
|
26
|
+
reason: string;
|
|
27
|
+
};
|
|
28
|
+
interface EntryContext {
|
|
29
|
+
checkout: string;
|
|
30
|
+
entry: MarketplaceEntry;
|
|
31
|
+
}
|
|
32
|
+
interface EntryChain {
|
|
33
|
+
next(context: EntryContext): EntryResolution | Promise<EntryResolution>;
|
|
34
|
+
}
|
|
35
|
+
/** One handler in the marketplace-entry chain. */
|
|
36
|
+
export interface EntryHandler {
|
|
37
|
+
name: string;
|
|
38
|
+
handle(context: EntryContext, chain: EntryChain): EntryResolution | Promise<EntryResolution>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Canonical `https://host/owner/repo` form of a git URL, for equality
|
|
42
|
+
* comparisons between a source's configured URL and an entry's remote.
|
|
43
|
+
*/
|
|
44
|
+
export declare function canonicalGitUrl(url: string): string;
|
|
45
|
+
/** The remote URL an entry points at, across every dialect's shape. */
|
|
46
|
+
export declare function entryRemoteUrl(entry: MarketplaceEntry): string | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve one marketplace entry's source against its checkout. Self-
|
|
49
|
+
* references (an entry pointing back at this very source, as Claude Code
|
|
50
|
+
* ships for single-repo marketplaces) resolve to the local checkout so the
|
|
51
|
+
* repo's own manifest and surfaces are scanned directly.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveMarketplaceEntry(checkout: string, entry: MarketplaceEntry, sourceUrl: string | undefined): Promise<EntryResolution>;
|
|
54
|
+
/** Read one checkout through marketplace manifests, dialect by dialect. */
|
|
55
|
+
export declare class MarketplaceStrategy implements ScanFilter {
|
|
56
|
+
readonly name = "marketplace";
|
|
57
|
+
doScan(context: ScanContext, chain: ScanChain): Promise<ScanResolution>;
|
|
58
|
+
private marketplaceRoots;
|
|
59
|
+
}
|
|
60
|
+
/** Read nested plugin roots up to four levels deep. */
|
|
61
|
+
export declare class RootedStrategy implements ScanFilter {
|
|
62
|
+
readonly name = "rooted";
|
|
63
|
+
doScan(context: ScanContext, chain: ScanChain): Promise<ScanResolution>;
|
|
64
|
+
}
|
|
65
|
+
/** Terminal fallback: manifest-less flat `<child>/SKILL.md` collections. */
|
|
66
|
+
export declare class FlatCollectionsStrategy implements ScanFilter {
|
|
67
|
+
readonly name = "flat-collections";
|
|
68
|
+
doScan(context: ScanContext): Promise<ScanResolution>;
|
|
69
|
+
}
|
|
70
|
+
/** The default chain, most specific first with a terminal fallback. */
|
|
71
|
+
export declare function defaultScanFilters(): readonly ScanFilter[];
|
|
72
|
+
/** Discover every suite under one source checkout. */
|
|
73
|
+
export declare function discoverSuitesInSource(checkoutDir: string, sourceId: string, dimension: SuiteDimension, sourceUrl?: string): Promise<Suite[]>;
|
|
74
|
+
/** Scan one checkout through the filter chain with full diagnostics. */
|
|
75
|
+
export declare function scanSource(checkoutDir: string, sourceId: string, dimension: SuiteDimension, sourceUrl?: string): Promise<ScanResult>;
|
|
76
|
+
/** Whether a directory carries any known suite manifest. */
|
|
77
|
+
export declare function hasSuiteManifest(dir: string): Promise<boolean>;
|
|
78
|
+
/** Whether a directory carries skill files in the flat or bundled shape. */
|
|
79
|
+
export declare function hasSkillFiles(dir: string): Promise<boolean>;
|
|
80
|
+
/** Read one suite root into the normalized shape, or undefined when no manifest parses. */
|
|
81
|
+
export declare function readSuite(root: string, sourceId: string, dimension: SuiteDimension, hint: SuiteHint | undefined): Promise<Suite | undefined>;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import type { SourceRef, Suite, SuiteDimension } from '../model/types.js';
|
|
2
2
|
/** Discover suites from the selected configured or project checkouts. */
|
|
3
3
|
export declare function discoverSourceList(sources: SourceRef[], dimension: SuiteDimension, dimensionRoot: string): Promise<Suite[]>;
|
|
4
|
+
/** Discover suites plus per-source scan diagnostics for one dimension. */
|
|
5
|
+
export declare function discoverSourceListWithNotes(sources: SourceRef[], dimension: SuiteDimension, dimensionRoot: string): Promise<{
|
|
6
|
+
suites: Suite[];
|
|
7
|
+
scanNotes: Record<string, string[]>;
|
|
8
|
+
}>;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan one source checkout into normalized suites.
|
|
3
|
+
*
|
|
4
|
+
* The actual discovery lives in the strategy chain (`scan-pipeline.ts` +
|
|
5
|
+
* `scan-resolvers.ts`); this module is the compatibility facade that keeps
|
|
6
|
+
* the historical imports (`discoverSuitesInSource`, `repoName`,
|
|
7
|
+
* `listMdFiles`, `LspEntry`) stable for callers and tests.
|
|
8
|
+
*/
|
|
1
9
|
import type { Suite, SuiteDimension } from '../model/types.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export {
|
|
5
|
-
export
|
|
10
|
+
export { repoName, listMdFiles, discoverLspEntries, scanSource, canonicalGitUrl, resolveMarketplaceEntry, defaultScanFilters, MarketplaceStrategy, RootedStrategy, FlatCollectionsStrategy } from './scan-resolvers.js';
|
|
11
|
+
export type { MarketplaceEntry, EntryResolution, EntryHandler, SuiteHint } from './scan-resolvers.js';
|
|
12
|
+
export type { LspEntry } from './surfaces.js';
|
|
13
|
+
export { runScanChain } from './scan-pipeline.js';
|
|
14
|
+
export type { ScanContext, ScanFilter, ScanChain, ScanResolution, ScanAttempt, ScanResult } from './scan-pipeline.js';
|
|
6
15
|
/** Discover every suite under one source checkout. */
|
|
7
|
-
export declare function discoverSuitesInSource(checkoutDir: string, sourceId: string, dimension: SuiteDimension): Promise<Suite[]>;
|
|
8
|
-
/** Whether a suite root path lies outside the checkout. */
|
|
9
|
-
export declare function isOutside(root: string, candidate: string): boolean;
|
|
16
|
+
export declare function discoverSuitesInSource(checkoutDir: string, sourceId: string, dimension: SuiteDimension, sourceUrl?: string): Promise<Suite[]>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { McpSuiteConfig, SuiteSkill, SuiteSurfaceCounts } from '../model/types.js';
|
|
1
|
+
import type { LspSuiteConfig, McpSuiteConfig, SuiteSkill, SuiteSurfaceCounts } from '../model/types.js';
|
|
2
2
|
/** Discover SKILL.md files under the suite's skills directory, up to 3 levels deep. */
|
|
3
3
|
export declare function discoverSkills(root: string, errors: string[], declared?: unknown): Promise<SuiteSkill[]>;
|
|
4
4
|
/** Read the suite's MCP config: `mcp.json` or `.mcp.json`, else the winning manifest's inline `mcpServers`. */
|
|
5
5
|
export declare function discoverMcp(root: string, errors: string[]): Promise<McpSuiteConfig | undefined>;
|
|
6
|
-
/** Count surfaces for a suite; mcp counts only validated servers. */
|
|
7
|
-
export declare function countSurfaces(root: string, skills: SuiteSkill[], mcp: McpSuiteConfig | undefined): Promise<SuiteSurfaceCounts>;
|
|
6
|
+
/** Count surfaces for a suite; mcp counts only validated servers, lsp counts inline servers plus directory entries. */
|
|
7
|
+
export declare function countSurfaces(root: string, skills: SuiteSkill[], mcp: McpSuiteConfig | undefined, lsp?: LspSuiteConfig): Promise<SuiteSurfaceCounts>;
|
|
8
8
|
export interface LspEntry {
|
|
9
9
|
name: string;
|
|
10
10
|
path: string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Browser-safe LSP status records shared by host aggregation and client rendering. */
|
|
2
|
+
/** Whether an LSP row comes from a suite declaration or direct user configuration. */
|
|
3
|
+
export type LspStatusKind = 'plugin' | 'direct';
|
|
4
|
+
/** Operational state rendered for an LSP server row. */
|
|
5
|
+
export type LspStatusState = 'mounted' | 'starting' | 'host-missing' | 'failed' | 'conflict' | 'disabled';
|
|
6
|
+
/**
|
|
7
|
+
* One declared language-server row for the status surface.
|
|
8
|
+
*
|
|
9
|
+
* Rows are built from the enabled suites' inline `lspServers` declarations
|
|
10
|
+
* plus the user's direct configuration, merged with the latest mount
|
|
11
|
+
* diagnostics; the DSH `ctx.lsp` seam exposes no provider snapshot, so this
|
|
12
|
+
* is a declaration-and-diagnostic model, not a process probe.
|
|
13
|
+
*/
|
|
14
|
+
export interface LspStatusEntry {
|
|
15
|
+
/** Stable row id: `${suiteId}/${serverKey}` (suite rows) or `direct/${serverKey}`. */
|
|
16
|
+
id: string;
|
|
17
|
+
/** Server key from the declaring `lspServers` table. */
|
|
18
|
+
serverKey: string;
|
|
19
|
+
/** Declaring suite id; the sentinel `direct` for user-configured rows. */
|
|
20
|
+
suiteId: string;
|
|
21
|
+
/** Declaring suite display name. */
|
|
22
|
+
suiteName: string;
|
|
23
|
+
/** Source id of the declaring suite; empty for user-configured rows. */
|
|
24
|
+
sourceId: string;
|
|
25
|
+
/** Where the row comes from. */
|
|
26
|
+
kind: LspStatusKind;
|
|
27
|
+
/** Executable the host will spawn. */
|
|
28
|
+
command: string;
|
|
29
|
+
/** Executable arguments. */
|
|
30
|
+
args: string[];
|
|
31
|
+
/** Lowercase leading-dot extension → LSP language id. */
|
|
32
|
+
extensions: Record<string, string>;
|
|
33
|
+
/** Operational state. */
|
|
34
|
+
state: LspStatusState;
|
|
35
|
+
/** Latest diagnostic reason, when the state is not `mounted`/`disabled`. */
|
|
36
|
+
reason?: string;
|
|
37
|
+
/** Whether a failed mount will be retried automatically. */
|
|
38
|
+
retryable?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** The LSP status response returned by the host. */
|
|
41
|
+
export interface LspStatusPayload {
|
|
42
|
+
entries: LspStatusEntry[];
|
|
43
|
+
observedAt: string;
|
|
44
|
+
totals: {
|
|
45
|
+
all: number;
|
|
46
|
+
mounted: number;
|
|
47
|
+
failed: number;
|
|
48
|
+
blocked: number;
|
|
49
|
+
disabled: number;
|
|
50
|
+
};
|
|
51
|
+
/** True when the host lacks the LSP packages, so every declaration is blocked. */
|
|
52
|
+
hostMissing: boolean;
|
|
53
|
+
}
|
|
@@ -5,12 +5,15 @@ export declare const MARKET_API_PREFIX: "/api/agent-plugins/";
|
|
|
5
5
|
export declare const MARKET_ROUTES: {
|
|
6
6
|
readonly overview: "/api/agent-plugins/overview";
|
|
7
7
|
readonly mcpStatus: "/api/agent-plugins/mcp-status";
|
|
8
|
+
readonly lspStatus: "/api/agent-plugins/lsp-status";
|
|
9
|
+
readonly lspServers: "/api/agent-plugins/lsp-servers";
|
|
8
10
|
readonly progress: "/api/agent-plugins/progress";
|
|
9
11
|
readonly config: "/api/agent-plugins/config";
|
|
10
12
|
readonly suite: "/api/agent-plugins/suite";
|
|
11
13
|
readonly skill: "/api/agent-plugins/skill";
|
|
12
14
|
readonly addSource: "/api/agent-plugins/sources/add";
|
|
13
15
|
readonly updateSource: "/api/agent-plugins/sources/update";
|
|
16
|
+
readonly adoptSource: "/api/agent-plugins/sources/adopt";
|
|
14
17
|
readonly removeSource: "/api/agent-plugins/sources/remove";
|
|
15
18
|
readonly refreshSource: "/api/agent-plugins/sources/refresh";
|
|
16
19
|
readonly install: "/api/agent-plugins/install";
|
|
@@ -19,16 +22,47 @@ export declare const MARKET_ROUTES: {
|
|
|
19
22
|
readonly setSurface: "/api/agent-plugins/set-surface";
|
|
20
23
|
readonly mcpOverrides: "/api/agent-plugins/mcp-overrides";
|
|
21
24
|
readonly setMcpOverride: "/api/agent-plugins/set-mcp-override";
|
|
25
|
+
readonly mcpRetry: "/api/agent-plugins/mcp-retry";
|
|
26
|
+
readonly mcpReauthorize: "/api/agent-plugins/mcp-reauthorize";
|
|
27
|
+
readonly mcpBackend: "/api/agent-plugins/mcp-backend";
|
|
28
|
+
readonly setMcpBackend: "/api/agent-plugins/set-mcp-backend";
|
|
22
29
|
};
|
|
30
|
+
/** The MCP mount backend state reported to the settings page. */
|
|
31
|
+
export interface McpBackendPayload {
|
|
32
|
+
backend: 'builtin' | 'host';
|
|
33
|
+
/** Whether the host `dsh-mcp-client` resolves from the plugin context. */
|
|
34
|
+
hostClient: {
|
|
35
|
+
available: boolean;
|
|
36
|
+
version?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Download region: the persisted setting and its locale-resolved route. */
|
|
39
|
+
downloadRegion: {
|
|
40
|
+
setting: 'auto' | 'global' | 'china';
|
|
41
|
+
effective: 'global' | 'china';
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** One unmanaged `.sources/` checkout the user can adopt as a source. */
|
|
45
|
+
export interface UnmanagedSource {
|
|
46
|
+
id: string;
|
|
47
|
+
/** The checkout's `origin` remote URL; absent for non-git directories. */
|
|
48
|
+
url?: string;
|
|
49
|
+
}
|
|
23
50
|
/** A configured source row returned to the market client. */
|
|
24
51
|
export interface SourceOverview {
|
|
25
52
|
id: string;
|
|
26
53
|
url: string;
|
|
27
54
|
branch?: string;
|
|
28
55
|
local?: boolean;
|
|
56
|
+
/** Acquisition kind (`git` / `local` / `archive`); `local` mirrors the legacy flag. */
|
|
57
|
+
kind: string;
|
|
58
|
+
/** The checkout pre-existed (manually cloned or adopted); never deleted on removal. */
|
|
59
|
+
adopted?: boolean;
|
|
29
60
|
cloned: boolean;
|
|
30
61
|
lockCommit?: string;
|
|
31
62
|
error?: string;
|
|
63
|
+
/** Scanner diagnostics for this source (dropped entries, fallbacks taken);
|
|
64
|
+
* absent when the scan completed with no notes. */
|
|
65
|
+
scanNotes?: string[];
|
|
32
66
|
suiteIds: string[];
|
|
33
67
|
}
|
|
34
68
|
/** Counts of runtime surfaces displayed on a suite card. */
|
|
@@ -47,6 +81,7 @@ export interface SuiteSurfaceToggles {
|
|
|
47
81
|
hooks: boolean;
|
|
48
82
|
commands: boolean;
|
|
49
83
|
agents: boolean;
|
|
84
|
+
lsp: boolean;
|
|
50
85
|
}
|
|
51
86
|
/** One server's persisted MCP override (wire shape mirrors runtime types). */
|
|
52
87
|
export type McpServerOverrideWire = {
|
|
@@ -90,6 +125,8 @@ export interface OverviewPayload {
|
|
|
90
125
|
user: string;
|
|
91
126
|
data: string;
|
|
92
127
|
};
|
|
128
|
+
/** Unmanaged `.sources/` checkouts (manual clones) available for adoption. */
|
|
129
|
+
unmanaged?: UnmanagedSource[];
|
|
93
130
|
}
|
|
94
131
|
/** Host-side progress of the source mutation currently in flight. */
|
|
95
132
|
export interface SourceProgress {
|
|
@@ -119,6 +156,21 @@ export interface LspPreview {
|
|
|
119
156
|
name: string;
|
|
120
157
|
content: string;
|
|
121
158
|
}
|
|
159
|
+
/** One inline-declared LSP server in a suite detail response. */
|
|
160
|
+
export interface LspServerPreview {
|
|
161
|
+
/** Server key from the declaring `lspServers` table. */
|
|
162
|
+
key: string;
|
|
163
|
+
command: string;
|
|
164
|
+
args: string[];
|
|
165
|
+
/** Lowercase leading-dot extension → LSP language id. */
|
|
166
|
+
extensions: Record<string, string>;
|
|
167
|
+
env?: Record<string, string>;
|
|
168
|
+
}
|
|
169
|
+
/** The suite's LSP surface: inline-declared servers plus directory definition files. */
|
|
170
|
+
export interface LspSurfaceDetail {
|
|
171
|
+
servers: LspServerPreview[];
|
|
172
|
+
raw: LspPreview[];
|
|
173
|
+
}
|
|
122
174
|
/** One flattened hook entry in a suite detail response. */
|
|
123
175
|
export interface HookPreview {
|
|
124
176
|
event: string;
|
|
@@ -135,6 +187,8 @@ export interface McpServerDetail {
|
|
|
135
187
|
env?: Record<string, string>;
|
|
136
188
|
cwd?: string;
|
|
137
189
|
headers?: Record<string, string>;
|
|
190
|
+
/** External credential references used by env/header/argument placeholders. */
|
|
191
|
+
credentialRefs: string[];
|
|
138
192
|
}
|
|
139
193
|
/** Full suite detail response served by the detail modal. */
|
|
140
194
|
export interface SuiteDetail {
|
|
@@ -162,7 +216,7 @@ export interface SuiteDetail {
|
|
|
162
216
|
};
|
|
163
217
|
commands: MarkdownPreview[];
|
|
164
218
|
agents: MarkdownPreview[];
|
|
165
|
-
lsp:
|
|
219
|
+
lsp: LspSurfaceDetail;
|
|
166
220
|
errors: string[];
|
|
167
221
|
mcpErrors: string[];
|
|
168
222
|
}
|
|
@@ -6,8 +6,8 @@ export interface McpStatusTool {
|
|
|
6
6
|
}
|
|
7
7
|
/** Whether an MCP row comes from a suite or direct host observation. */
|
|
8
8
|
export type McpStatusKind = 'plugin' | 'direct';
|
|
9
|
-
/** Operational state rendered for an MCP row. */
|
|
10
|
-
export type McpStatusState = 'connected' | 'degraded' | 'failed' | 'disabled';
|
|
9
|
+
/** Operational state rendered for an MCP row. `foreign` = mounted by another MCP client (informational). */
|
|
10
|
+
export type McpStatusState = 'connected' | 'degraded' | 'failed' | 'needs-credentials' | 'orphaned' | 'disabled' | 'foreign';
|
|
11
11
|
/** One MCP service row for the status surface. */
|
|
12
12
|
export interface McpStatusEntry {
|
|
13
13
|
id: string;
|
|
@@ -22,6 +22,15 @@ export interface McpStatusEntry {
|
|
|
22
22
|
config?: Record<string, unknown>;
|
|
23
23
|
tools: McpStatusTool[];
|
|
24
24
|
reason?: string;
|
|
25
|
+
/** Mount-path classification when a diagnostic produced this row. */
|
|
26
|
+
code?: 'unsupported-transport' | 'missing-credential' | 'credential-error' | 'unmount-failed' | 'mount-failed' | 'foreign-mount';
|
|
27
|
+
/** Environment-variable credential references required by this server. */
|
|
28
|
+
credentialRefs?: string[];
|
|
29
|
+
/** Whether this server advertised zero tools at observation time. Zero-tool
|
|
30
|
+
* servers are legitimate, so the panel never treats `degraded` as broken. */
|
|
31
|
+
advertisedTools?: boolean;
|
|
32
|
+
/** Whether a failed server will be retried automatically. */
|
|
33
|
+
retryable?: boolean;
|
|
25
34
|
}
|
|
26
35
|
/** The MCP status response returned by the host. */
|
|
27
36
|
export interface McpStatusPayload {
|
|
@@ -32,7 +41,10 @@ export interface McpStatusPayload {
|
|
|
32
41
|
connected: number;
|
|
33
42
|
degraded: number;
|
|
34
43
|
failed: number;
|
|
44
|
+
needsCredentials: number;
|
|
45
|
+
orphaned: number;
|
|
35
46
|
disabled: number;
|
|
47
|
+
foreign: number;
|
|
36
48
|
};
|
|
37
49
|
directObservationOnly: boolean;
|
|
38
50
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Function plugin (named exports, no default export). It registers one skill
|
|
5
5
|
* provider feeding enabled suites into `ctx.skills`, reconciles enabled
|
|
6
|
-
* suites' `mcp.json` servers into live
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* suites' `mcp.json` servers into live self-built bridge mounts (stdio,
|
|
7
|
+
* Streamable HTTP with OAuth, and legacy SSE — no host MCP client needed),
|
|
8
|
+
* and mounts the market page's HTTP routes on the web server. Skills and MCP
|
|
9
|
+
* tools are exposed through the host's native model surfaces; this plugin
|
|
10
|
+
* does not register a redundant suite-inventory model tool.
|
|
10
11
|
*
|
|
11
|
-
* Requires `ctx.skills` (the dsh skill registry).
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Requires `ctx.skills` (the dsh skill registry). MCP mounting is
|
|
13
|
+
* self-contained: suites' MCP servers mount through the market's own bridge
|
|
14
|
+
* plugin on the host `tools` registry.
|
|
14
15
|
*/
|
|
15
16
|
import type { Context } from '@deepseek-ai/cordis';
|
|
16
17
|
import type { SourceRef } from './model/types.js';
|
|
@@ -20,9 +21,24 @@ export declare const inject: string[];
|
|
|
20
21
|
export interface Config {
|
|
21
22
|
/** User-dimension suite root; defaults to `~/.dsh/agent-plugins` (`$DSH_HOME/agent-plugins`). */
|
|
22
23
|
userRoot?: string;
|
|
23
|
-
/** Per-suite data root backing `${PLUGIN_DATA}
|
|
24
|
+
/** Per-suite data root backing `${PLUGIN_DATA}` and MCP overrides; defaults to `<userRoot>/data`. */
|
|
24
25
|
dataRoot?: string;
|
|
25
26
|
/** Initial repository sources, merged into the persisted state on first load. */
|
|
26
27
|
sources?: SourceRef[];
|
|
28
|
+
/**
|
|
29
|
+
* Git/archive acquisition tuning: `proxy` (http/https proxy URL),
|
|
30
|
+
* `insteadOf` URL-prefix rewrites (mirror acceleration), `timeoutMs` per
|
|
31
|
+
* git invocation, `cloneRetry` (default true), `fallbackTarball` (retry a
|
|
32
|
+
* failed GitHub clone as a codeload tarball download; default false), and
|
|
33
|
+
* `allowHttpArchives` (permit plain-http archive URLs; default false).
|
|
34
|
+
*/
|
|
35
|
+
git?: {
|
|
36
|
+
proxy?: string;
|
|
37
|
+
insteadOf?: Record<string, string>;
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
cloneRetry?: boolean;
|
|
40
|
+
fallbackTarball?: boolean;
|
|
41
|
+
allowHttpArchives?: boolean;
|
|
42
|
+
};
|
|
27
43
|
}
|
|
28
44
|
export declare function apply(ctx: Context, config?: Config): void;
|
|
@@ -7,17 +7,33 @@
|
|
|
7
7
|
* Codex `.codex-plugin/plugin.json`). Discovery maps every layout onto this
|
|
8
8
|
* internal shape; runtime injection consumes only the internal shape.
|
|
9
9
|
*/
|
|
10
|
+
/** How a source's content is acquired. */
|
|
11
|
+
export type SourceKind = 'git' | 'local' | 'archive';
|
|
10
12
|
/** One configured repository source. */
|
|
11
13
|
export interface SourceRef {
|
|
12
14
|
/** Stable local id; `[a-z0-9][a-z0-9-]*`, unique across sources. */
|
|
13
15
|
id: string;
|
|
14
|
-
/** Git URL
|
|
16
|
+
/** Git URL, archive (zip / tar.gz) URL, or a local directory path. */
|
|
15
17
|
url: string;
|
|
16
18
|
/** Optional branch to pin (git sources only). */
|
|
17
19
|
branch?: string;
|
|
18
|
-
/** Read the source directory directly instead of cloning it. */
|
|
20
|
+
/** Read the source directory directly instead of cloning it (legacy flag; `kind: 'local'`). */
|
|
19
21
|
local?: boolean;
|
|
22
|
+
/** Acquisition kind; inferred from the URL shape when omitted. */
|
|
23
|
+
kind?: SourceKind;
|
|
24
|
+
/** Expected SHA-256 of an archive download (archive sources only). */
|
|
25
|
+
sha256?: string;
|
|
26
|
+
/** The checkout pre-existed (manually cloned or adopted); never deleted on source removal. */
|
|
27
|
+
adopted?: boolean;
|
|
20
28
|
}
|
|
29
|
+
/** Whether a URL points at a downloadable archive. */
|
|
30
|
+
export declare function isArchiveUrl(url: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Effective acquisition kind of a source: the explicit `kind` wins, the
|
|
33
|
+
* legacy `local` flag maps to `'local'`, archive-shaped URLs infer
|
|
34
|
+
* `'archive'`, and everything else stays `'git'`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSourceKind(source: Pick<SourceRef, 'url' | 'local' | 'kind'>): SourceKind;
|
|
21
37
|
/** The manifest layout a suite root was discovered under. */
|
|
22
38
|
export type SuiteLayoutKind = 'agent-plugin-v1' | 'universal' | 'claude-code' | 'cursor' | 'kimi' | 'codex' | 'skill-collection' | 'remote' | 'project-native';
|
|
23
39
|
/** Normalized suite manifest fields. */
|
|
@@ -74,11 +90,21 @@ export interface McpServerStreamableHttp {
|
|
|
74
90
|
type: 'streamable-http';
|
|
75
91
|
url: string;
|
|
76
92
|
headers?: Record<string, string>;
|
|
93
|
+
/** Opt in to OAuth 2.1 authorization for servers that answer `401` with a challenge (on by default; `enabled: false` opts out). */
|
|
94
|
+
auth?: {
|
|
95
|
+
enabled: boolean;
|
|
96
|
+
scope?: string;
|
|
97
|
+
};
|
|
77
98
|
}
|
|
78
99
|
export interface McpServerSse {
|
|
79
100
|
type: 'sse';
|
|
80
101
|
url: string;
|
|
81
102
|
headers?: Record<string, string>;
|
|
103
|
+
/** OAuth 2.1 authorization, mirroring the streamable-http semantics. */
|
|
104
|
+
auth?: {
|
|
105
|
+
enabled: boolean;
|
|
106
|
+
scope?: string;
|
|
107
|
+
};
|
|
82
108
|
}
|
|
83
109
|
export type McpServer = McpServerStdio | McpServerStreamableHttp | McpServerSse;
|
|
84
110
|
/** Parsed and validated `mcp.json` content. */
|
|
@@ -86,6 +112,27 @@ export interface McpSuiteConfig {
|
|
|
86
112
|
schema: string;
|
|
87
113
|
servers: Record<string, McpServer>;
|
|
88
114
|
}
|
|
115
|
+
/** One normalized inline LSP server declaration (`lspServers` table entry). */
|
|
116
|
+
export interface LspServerSpec {
|
|
117
|
+
/** Server key from the declaring table (e.g. `typescript`). */
|
|
118
|
+
key: string;
|
|
119
|
+
/** Executable to spawn (resolved on PATH by the LSP host). */
|
|
120
|
+
command: string;
|
|
121
|
+
/** Arguments passed to the executable. Default `[]`. */
|
|
122
|
+
args: string[];
|
|
123
|
+
/** Lowercase leading-dot extension → LSP language id. */
|
|
124
|
+
extensionToLanguage: Record<string, string>;
|
|
125
|
+
/** Extra env vars merged over the ambient env. */
|
|
126
|
+
env?: Record<string, string>;
|
|
127
|
+
/** Static `initialize` options forwarded to the server. */
|
|
128
|
+
initializationOptions?: unknown;
|
|
129
|
+
/** Static answer to every `workspace/configuration` item. */
|
|
130
|
+
configuration?: unknown;
|
|
131
|
+
}
|
|
132
|
+
/** Parsed inline `lspServers` declarations of one suite. */
|
|
133
|
+
export interface LspSuiteConfig {
|
|
134
|
+
servers: Record<string, LspServerSpec>;
|
|
135
|
+
}
|
|
89
136
|
/** Install dimension of a suite. */
|
|
90
137
|
export type SuiteDimension = 'user' | 'project';
|
|
91
138
|
/** One discovered suite with runtime-relevant fields resolved. */
|
|
@@ -97,6 +144,8 @@ export interface Suite {
|
|
|
97
144
|
skills: SuiteSkill[];
|
|
98
145
|
/** Validated mcp.json content; absent when the file is missing or invalid. */
|
|
99
146
|
mcp?: McpSuiteConfig;
|
|
147
|
+
/** Parsed inline `lspServers` declarations; absent when the suite declares none. */
|
|
148
|
+
lsp?: LspSuiteConfig;
|
|
100
149
|
surfaces: SuiteSurfaceCounts;
|
|
101
150
|
dimension: SuiteDimension;
|
|
102
151
|
enabled: boolean;
|
|
@@ -114,7 +163,7 @@ export interface Suite {
|
|
|
114
163
|
errors: string[];
|
|
115
164
|
}
|
|
116
165
|
/** Runtime surfaces that can be selectively enabled per installed suite. */
|
|
117
|
-
export type SuiteSurfaceKey = 'skills' | 'mcp' | 'hooks' | 'commands' | 'agents';
|
|
166
|
+
export type SuiteSurfaceKey = 'skills' | 'mcp' | 'hooks' | 'commands' | 'agents' | 'lsp';
|
|
118
167
|
/** Per-surface user overrides; absent keys default to enabled. */
|
|
119
168
|
export type SurfaceOverrides = Partial<Record<SuiteSurfaceKey, boolean>>;
|
|
120
169
|
/** The full set of toggleable surfaces, in display order. */
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LspServerSpec } from '../model/types.js';
|
|
2
|
+
/** The direct LSP server configuration file path. */
|
|
3
|
+
export declare function lspServersPath(dataRoot: string): string;
|
|
4
|
+
/** Load the user-configured LSP servers; unreadable or invalid files yield an empty table. */
|
|
5
|
+
export declare function loadLspServers(dataRoot: string): Promise<{
|
|
6
|
+
servers: Record<string, LspServerSpec>;
|
|
7
|
+
errors: string[];
|
|
8
|
+
}>;
|
|
9
|
+
/** Validate and persist the user-configured LSP servers; returns normalized specs. */
|
|
10
|
+
export declare function saveLspServers(dataRoot: string, raw: unknown): Promise<{
|
|
11
|
+
servers: Record<string, LspServerSpec>;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime LSP mounts: one live `dsh-lsp-stdio` child plugin per enabled
|
|
3
|
+
* suite's inline `lspServers` table, mounted through `ctx.plugin`.
|
|
4
|
+
*
|
|
5
|
+
* Mounts reconcile against the enabled-suite set exactly like the MCP mounts:
|
|
6
|
+
* reconcile() unmounts rows whose suite was disabled or removed and mounts
|
|
7
|
+
* rows that appeared. The host LSP package is optional at runtime — without
|
|
8
|
+
* it, suites keep every other surface and the manager reports a one-line
|
|
9
|
+
* `host-missing` diagnostic that does not enter the retry schedule (a missing
|
|
10
|
+
* package is not a transient failure). Mount failures that can resolve after
|
|
11
|
+
* user action (installing the language server executable) do retry.
|
|
12
|
+
*
|
|
13
|
+
* Provider identity: one `${suiteId}/${serverKey}` provider id per server, so
|
|
14
|
+
* two suites declaring the same server key mount independently. Extension
|
|
15
|
+
* ownership in `ctx.lsp` is exclusive by design; when two enabled suites
|
|
16
|
+
* claim the same extension the later mount fails with `seam-conflict` and the
|
|
17
|
+
* user resolves it through per-suite surface toggles.
|
|
18
|
+
*/
|
|
19
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
20
|
+
import type { Suite } from '../model/types.js';
|
|
21
|
+
export interface LspMountDiagnostic {
|
|
22
|
+
suiteId: string;
|
|
23
|
+
serverKey: string;
|
|
24
|
+
reason: string;
|
|
25
|
+
code?: 'mount-failed' | 'unmount-failed' | 'seam-conflict' | 'host-missing';
|
|
26
|
+
}
|
|
27
|
+
/** One dsh-lsp-stdio server configuration row (its Config.servers entry). */
|
|
28
|
+
export interface LspStdioServerConfig {
|
|
29
|
+
command: string;
|
|
30
|
+
args: string[];
|
|
31
|
+
extensionToLanguage: Record<string, string>;
|
|
32
|
+
env?: Record<string, string>;
|
|
33
|
+
initializationOptions?: unknown;
|
|
34
|
+
configuration?: unknown;
|
|
35
|
+
}
|
|
36
|
+
/** Build one dsh-lsp-stdio Config.servers entry from a normalized spec. */
|
|
37
|
+
export declare function toLspServerConfig(spec: {
|
|
38
|
+
command: string;
|
|
39
|
+
args: string[];
|
|
40
|
+
extensionToLanguage: Record<string, string>;
|
|
41
|
+
env?: Record<string, string>;
|
|
42
|
+
initializationOptions?: unknown;
|
|
43
|
+
configuration?: unknown;
|
|
44
|
+
}): LspStdioServerConfig;
|
|
45
|
+
/** Minimal structural shape of the dynamically imported `dsh-lsp-stdio` module. */
|
|
46
|
+
interface LspStdioModule {
|
|
47
|
+
default?: unknown;
|
|
48
|
+
}
|
|
49
|
+
export declare class LspMountRegistry {
|
|
50
|
+
private readonly ctx;
|
|
51
|
+
private readonly live;
|
|
52
|
+
/** Serialize mount and unmount passes so a disable cannot race an in-flight spawn. */
|
|
53
|
+
private reconcileQueue;
|
|
54
|
+
/** Pending retry timers keyed by mount key, so a teardown can cancel them. */
|
|
55
|
+
private readonly retries;
|
|
56
|
+
/** Attempt count per mount key; reset whenever a retry succeeds. */
|
|
57
|
+
private readonly attempts;
|
|
58
|
+
/** Snapshot of the last reconciled suite set, replayed by retry passes. */
|
|
59
|
+
private lastEnabled;
|
|
60
|
+
/** Host module loader; overridable for tests. */
|
|
61
|
+
private loadHost;
|
|
62
|
+
/** Latest diagnostic per suite id; cleared when its suite mounts or leaves the wanted set. */
|
|
63
|
+
private readonly lastDiagnostics;
|
|
64
|
+
/** Direct (user-configured) server provider; defaults to none. */
|
|
65
|
+
private directProvider;
|
|
66
|
+
constructor(ctx: Context, loadHost?: () => Promise<LspStdioModule | undefined>);
|
|
67
|
+
/** Queue one reconciliation behind any in-flight mount/unmount pass. */
|
|
68
|
+
reconcile(enabledSuites: Suite[]): Promise<LspMountDiagnostic[]>;
|
|
69
|
+
/** Mount/unmount LSP servers to match the enabled suites plus direct config exactly. */
|
|
70
|
+
private reconcileNow;
|
|
71
|
+
/** Install the direct (user-configured) server provider used at reconcile time. */
|
|
72
|
+
setDirectProvider(provider: () => Promise<Record<string, import('../model/types.js').LspServerSpec>>): void;
|
|
73
|
+
/** The latest mount diagnostic per suite, for the LSP status surface. */
|
|
74
|
+
diagnosticsSnapshot(): Map<string, LspMountDiagnostic>;
|
|
75
|
+
/** Whether at least one suite mount is live. */
|
|
76
|
+
hasLiveMounts(): boolean;
|
|
77
|
+
/** Mount one suite's full server table as a single `dsh-lsp-stdio` instance. */
|
|
78
|
+
private mountWith;
|
|
79
|
+
private unmount;
|
|
80
|
+
/**
|
|
81
|
+
* Schedule a delayed re-attempt for a mount that still is not live. A
|
|
82
|
+
* `host-missing` failure passes no diagnostic and is never retried; the
|
|
83
|
+
* schedule is bounded and resets with every reconcile pass.
|
|
84
|
+
*/
|
|
85
|
+
private scheduleRetry;
|
|
86
|
+
/** Dispose every live mount after queued reconciliation passes settle. */
|
|
87
|
+
disposeAll(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSP status aggregation: declared language servers of enabled+installed
|
|
3
|
+
* suites and the user's direct configuration, merged with the mount
|
|
4
|
+
* registry's latest diagnostics into rows for the status surface.
|
|
5
|
+
*
|
|
6
|
+
* The DSH `ctx.lsp` seam exposes no provider snapshot and no process probe,
|
|
7
|
+
* so a row's state is a declaration-and-diagnostic judgment: a suite whose
|
|
8
|
+
* mount succeeded yields `mounted` (the seam guarantees registration), a
|
|
9
|
+
* stored diagnostic yields its own state, and a declaration with neither
|
|
10
|
+
* mounts nor diagnostics means the host packages are absent (`host-missing`).
|
|
11
|
+
* Direct user-configured rows follow the same model under the sentinel suite
|
|
12
|
+
* id `direct` (mirroring mcp-status's `plugin`/`direct` split).
|
|
13
|
+
*/
|
|
14
|
+
import type { LspStatusPayload } from '../contracts/lsp-status.js';
|
|
15
|
+
import type { LspMountDiagnostic } from './lsp-mounts.js';
|
|
16
|
+
import type { LspServerSpec, Suite } from '../model/types.js';
|
|
17
|
+
/** Sentinel suite id for user-configured (non-suite) LSP servers. */
|
|
18
|
+
export declare const DIRECT_LSP_SUITE_ID = "direct";
|
|
19
|
+
/** The subset of LspMountRegistry the aggregator consumes (structural, for tests). */
|
|
20
|
+
export interface LspMountStatusSource {
|
|
21
|
+
diagnosticsSnapshot(): Map<string, LspMountDiagnostic>;
|
|
22
|
+
hasLiveMounts(): boolean;
|
|
23
|
+
}
|
|
24
|
+
/** The direct servers table the aggregator merges in (structural, for tests). */
|
|
25
|
+
export interface LspDirectServersSource {
|
|
26
|
+
servers: Record<string, LspServerSpec>;
|
|
27
|
+
errors: string[];
|
|
28
|
+
}
|
|
29
|
+
/** Build the status payload from declarations, direct configuration, and mount diagnostics. */
|
|
30
|
+
export declare function buildLspStatus(suites: readonly Suite[], registry: LspMountStatusSource, direct?: LspDirectServersSource): LspStatusPayload;
|