dsh-agent-plugins-market 0.8.0 → 0.8.2
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 +2 -2
- package/README.zh.md +2 -2
- package/client/client.js +1594 -1732
- package/client/client.js.map +1 -1
- package/lib/application/agent-roles.js +53 -0
- package/lib/application/catalog-context.js +2 -2
- package/lib/application/catalog.js +4 -8
- package/lib/{runtime → application}/deadline.js +1 -1
- package/lib/application/details.js +3 -3
- package/lib/application/json-file.js +43 -0
- package/lib/{runtime → application/lsp}/lsp-direct-config.js +9 -7
- package/lib/application/lsp/lsp-server-state.js +17 -0
- package/lib/{runtime → application/lsp}/lsp-status.js +22 -7
- package/lib/{runtime → application/lsp}/profile-seam.js +1 -1
- package/lib/application/lsp-service.js +5 -5
- package/lib/{runtime → application/mcp}/mcp-backend.js +6 -21
- package/lib/{runtime → application/mcp}/mcp-config.js +4 -4
- package/lib/{runtime → application/mcp}/mcp-direct-config.js +8 -49
- package/lib/{runtime → application/mcp}/mcp-overrides.js +3 -5
- package/lib/{runtime → application/mcp}/mcp-status.js +13 -7
- package/lib/application/mcp-service.js +11 -35
- package/lib/application/panel-resources.js +48 -11
- package/lib/{runtime → application/panels}/user-hooks.js +2 -2
- package/lib/{runtime → application/panels}/user-store.js +2 -2
- package/lib/application/ports.js +1 -0
- package/lib/application/project-agent-roles.js +1 -1
- package/lib/{runtime → application}/server-config.js +7 -17
- package/lib/application/snapshot-cache.js +1 -1
- package/lib/application/source-store.js +3 -4
- package/lib/{runtime → application/state}/state-store.js +5 -7
- package/lib/{runtime → application/state}/storage-migration.js +4 -4
- package/lib/catalog/source-catalog.js +0 -4
- package/lib/contracts/lsp.js +1 -0
- package/lib/contracts/market.js +0 -1
- package/lib/contracts/mcp.js +1 -0
- package/lib/index.js +64 -34
- package/lib/routes.js +2 -9
- package/lib/runtime/{agent-role-router.js → agents/agent-role-router.js} +7 -53
- package/lib/runtime/{subagent-catalog.js → agents/subagent-catalog.js} +24 -16
- package/lib/runtime/core/context.js +31 -0
- package/lib/runtime/{reconciler.js → core/reconciler.js} +5 -5
- package/lib/runtime/host/failure-detail.js +58 -0
- package/lib/runtime/{feedback-tool.js → host/feedback-tool.js} +1 -1
- package/lib/runtime/host/host-locale.js +83 -0
- package/lib/runtime/{settings-namespace.js → host/settings-namespace.js} +44 -66
- package/lib/runtime/host/shell-path.js +196 -0
- package/lib/runtime/{tool-registry-observer.js → host/tool-registry-observer.js} +2 -1
- package/lib/runtime/{lsp-mounts.js → lsp/lsp-mounts.js} +69 -20
- package/lib/runtime/{mcp-client → mcp/bridge}/bridge.js +52 -22
- package/lib/runtime/{mcp-client → mcp/bridge}/connection.js +2 -2
- package/lib/runtime/{mcp-client → mcp/bridge}/oauth.js +1 -1
- package/lib/runtime/{mcp-client → mcp/bridge}/tools.js +2 -2
- package/lib/runtime/{mcp-auth-record.js → mcp/mcp-auth-record.js} +1 -1
- package/lib/runtime/{mcp-mounts.js → mcp/mcp-mounts.js} +14 -7
- package/lib/runtime/{user-commands.js → panels/user-commands.js} +3 -3
- package/lib/runtime/{user-panels.js → panels/user-panels.js} +2 -2
- package/lib/runtime/{commands-mounts.js → surfaces/commands-mounts.js} +7 -7
- package/lib/runtime/{hooks-mounts.js → surfaces/hooks-mounts.js} +2 -2
- package/lib/runtime/{project-runtime.js → surfaces/project-runtime.js} +5 -5
- package/lib/runtime/{skills-provider.js → surfaces/skills-provider.js} +4 -4
- package/lib/types/application/agent-roles.d.ts +30 -0
- package/lib/types/application/catalog.d.ts +4 -7
- package/lib/types/application/details.d.ts +1 -1
- package/lib/types/application/json-file.d.ts +12 -0
- package/lib/types/{runtime → application/lsp}/lsp-direct-config.d.ts +1 -1
- package/lib/types/{runtime → application/lsp}/lsp-status.d.ts +3 -3
- package/lib/types/{runtime → application/mcp}/mcp-backend.d.ts +24 -22
- package/lib/types/{runtime/mcp-client/config.d.ts → application/mcp/mcp-bridge-config.d.ts} +11 -1
- package/lib/types/{runtime → application/mcp}/mcp-config.d.ts +6 -7
- package/lib/types/application/mcp/mcp-direct-config.d.ts +17 -0
- package/lib/types/{runtime → application/mcp}/mcp-overrides.d.ts +1 -1
- package/lib/types/{runtime → application/mcp}/mcp-status.d.ts +7 -7
- package/lib/types/application/mcp-service.d.ts +4 -11
- package/lib/types/application/panel-resources.d.ts +9 -2
- package/lib/types/{runtime → application/panels}/user-hooks.d.ts +1 -1
- package/lib/types/{runtime → application/panels}/user-store.d.ts +1 -1
- package/lib/types/application/ports.d.ts +17 -3
- package/lib/types/application/project-agent-roles.d.ts +1 -1
- package/lib/types/application/queries.d.ts +3 -6
- package/lib/types/{runtime → application}/regions.d.ts +1 -1
- package/lib/types/{runtime → application/state}/state-store.d.ts +2 -2
- package/lib/types/catalog/source-catalog.d.ts +0 -2
- package/lib/types/contracts/lsp-status.d.ts +6 -0
- package/lib/types/contracts/lsp.d.ts +16 -0
- package/lib/types/contracts/market.d.ts +1 -4
- package/lib/types/contracts/mcp-status.d.ts +21 -2
- package/lib/types/contracts/mcp.d.ts +20 -0
- package/lib/types/index.d.ts +87 -1
- package/lib/types/model/types.d.ts +0 -14
- package/lib/types/runtime/{agent-role-router.d.ts → agents/agent-role-router.d.ts} +3 -28
- package/lib/types/runtime/{subagent-catalog.d.ts → agents/subagent-catalog.d.ts} +6 -6
- package/lib/types/runtime/core/context.d.ts +14 -0
- package/lib/types/runtime/{reconcile-scheduler.d.ts → core/reconcile-scheduler.d.ts} +2 -2
- package/lib/types/runtime/{reconciler.d.ts → core/reconciler.d.ts} +8 -8
- package/lib/types/runtime/host/failure-detail.d.ts +6 -0
- package/lib/types/runtime/host/host-locale.d.ts +66 -0
- package/lib/types/runtime/{model-catalog.d.ts → host/model-catalog.d.ts} +1 -1
- package/lib/types/runtime/{settings-namespace.d.ts → host/settings-namespace.d.ts} +42 -32
- package/lib/types/runtime/host/shell-path.d.ts +70 -0
- package/lib/types/runtime/{lsp-mounts.d.ts → lsp/lsp-mounts.d.ts} +17 -11
- package/lib/types/runtime/{mcp-client → mcp/bridge}/bridge.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/connection.d.ts +3 -11
- package/lib/types/runtime/{mcp-client → mcp/bridge}/host-contract.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/oauth.d.ts +1 -1
- package/lib/types/runtime/{mcp-client → mcp/bridge}/transport.d.ts +1 -1
- package/lib/types/runtime/{mcp-auth-record.d.ts → mcp/mcp-auth-record.d.ts} +1 -1
- package/lib/types/runtime/{mcp-credentials.d.ts → mcp/mcp-credentials.d.ts} +1 -1
- package/lib/types/runtime/{mcp-mounts.d.ts → mcp/mcp-mounts.d.ts} +5 -11
- package/lib/types/runtime/{user-commands.d.ts → panels/user-commands.d.ts} +1 -1
- package/lib/types/runtime/{user-panels.d.ts → panels/user-panels.d.ts} +1 -1
- package/lib/types/runtime/{commands-mounts.d.ts → surfaces/commands-mounts.d.ts} +2 -2
- package/lib/types/runtime/{hooks-mounts.d.ts → surfaces/hooks-mounts.d.ts} +1 -1
- package/lib/types/runtime/{project-runtime.d.ts → surfaces/project-runtime.d.ts} +3 -3
- package/lib/types/runtime/{skills-provider.d.ts → surfaces/skills-provider.d.ts} +1 -1
- package/package.json +39 -33
- package/lib/runtime/host-locale.js +0 -89
- package/lib/runtime/legacy-root-migration.js +0 -12
- package/lib/runtime/lsp-server-state.js +0 -19
- package/lib/runtime/mcp-client/json-schema-subset.js +0 -181
- package/lib/types/runtime/host-locale.d.ts +0 -31
- package/lib/types/runtime/legacy-root-migration.d.ts +0 -2
- package/lib/types/runtime/mcp-client/json-schema-subset.d.ts +0 -58
- package/lib/types/runtime/mcp-direct-config.d.ts +0 -39
- /package/lib/{runtime/mcp-client/config.js → application/mcp/mcp-bridge-config.js} +0 -0
- /package/lib/{runtime → application/mcp}/mcp-redaction.js +0 -0
- /package/lib/{runtime → application}/regions.js +0 -0
- /package/lib/runtime/{agent-role-names.js → agents/agent-role-names.js} +0 -0
- /package/lib/runtime/{mount-lifecycle.js → core/mount-lifecycle.js} +0 -0
- /package/lib/runtime/{reconcile-scheduler.js → core/reconcile-scheduler.js} +0 -0
- /package/lib/runtime/{source-auto-update.js → core/source-auto-update.js} +0 -0
- /package/lib/runtime/{timer-seat.js → core/timer-seat.js} +0 -0
- /package/lib/runtime/{model-catalog.js → host/model-catalog.js} +0 -0
- /package/lib/runtime/{plugin-message-source.js → host/plugin-message-source.js} +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/host-contract.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/host-seams.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/plugin-identity.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/projection.js +0 -0
- /package/lib/runtime/{mcp-client → mcp/bridge}/transport.js +0 -0
- /package/lib/runtime/{mcp-credentials.js → mcp/mcp-credentials.js} +0 -0
- /package/lib/runtime/{dynamic-context.js → surfaces/dynamic-context.js} +0 -0
- /package/lib/types/{runtime → application}/deadline.d.ts +0 -0
- /package/lib/types/{runtime → application/lsp}/lsp-server-state.d.ts +0 -0
- /package/lib/types/{runtime → application/lsp}/profile-seam.d.ts +0 -0
- /package/lib/types/{runtime → application/mcp}/mcp-redaction.d.ts +0 -0
- /package/lib/types/{runtime → application}/server-config.d.ts +0 -0
- /package/lib/types/{runtime → application/state}/storage-migration.d.ts +0 -0
- /package/lib/types/runtime/{agent-role-names.d.ts → agents/agent-role-names.d.ts} +0 -0
- /package/lib/types/runtime/{mount-lifecycle.d.ts → core/mount-lifecycle.d.ts} +0 -0
- /package/lib/types/runtime/{source-auto-update.d.ts → core/source-auto-update.d.ts} +0 -0
- /package/lib/types/runtime/{timer-seat.d.ts → core/timer-seat.d.ts} +0 -0
- /package/lib/types/runtime/{feedback-tool.d.ts → host/feedback-tool.d.ts} +0 -0
- /package/lib/types/runtime/{plugin-message-source.d.ts → host/plugin-message-source.d.ts} +0 -0
- /package/lib/types/runtime/{tool-registry-observer.d.ts → host/tool-registry-observer.d.ts} +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/host-seams.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/plugin-identity.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/projection.d.ts +0 -0
- /package/lib/types/runtime/{mcp-client → mcp/bridge}/tools.d.ts +0 -0
- /package/lib/types/runtime/{dynamic-context.d.ts → surfaces/dynamic-context.d.ts} +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { DIRECT_LSP_SUITE_ID } from '
|
|
2
|
-
import { SerialPassQueue, RetryScheduler } from '
|
|
3
|
-
import { describeLegacySeam, findLegacyLspSeams } from '
|
|
4
|
-
import { qualifiedSuiteId, suiteDataDir } from '
|
|
5
|
-
import { expandPluginPaths, pluginRootOf } from '
|
|
6
|
-
import {
|
|
1
|
+
import { DIRECT_LSP_SUITE_ID } from '../../application/lsp/lsp-status.js';
|
|
2
|
+
import { SerialPassQueue, RetryScheduler } from '../core/mount-lifecycle.js';
|
|
3
|
+
import { describeLegacySeam, findLegacyLspSeams } from '../../application/lsp/profile-seam.js';
|
|
4
|
+
import { qualifiedSuiteId, suiteDataDir } from '../../catalog/paths.js';
|
|
5
|
+
import { expandPluginPaths, pluginRootOf } from '../../catalog/plugin-variables.js';
|
|
6
|
+
import { causeMessages } from '../host/failure-detail.js';
|
|
7
|
+
import { resolveDeclaredCommand } from '../host/shell-path.js';
|
|
8
|
+
import { effectiveSurfaces } from '../../model/types.js';
|
|
7
9
|
/** Build one dsh-lsp-stdio Config.servers entry from a normalized spec. */
|
|
8
10
|
export function toLspServerConfig(spec) {
|
|
9
11
|
return {
|
|
@@ -110,16 +112,21 @@ export class LspMountRegistry {
|
|
|
110
112
|
// otherwise shadow each other's mount and diagnostics.
|
|
111
113
|
const key = qualifiedSuiteId(suite.sourceId, suite.id);
|
|
112
114
|
const config = {};
|
|
115
|
+
const facts = [];
|
|
116
|
+
const pathExtensions = [];
|
|
113
117
|
const root = pluginRootOf(suite);
|
|
114
118
|
const context = {
|
|
115
119
|
...(root === undefined ? {} : { root }),
|
|
116
120
|
...(root === undefined || this.pluginDataRoot === undefined ? {} : { data: suiteDataDir(this.pluginDataRoot, suite.sourceId, suite.id) })
|
|
117
121
|
};
|
|
118
|
-
for (const spec of servers)
|
|
119
|
-
if (
|
|
120
|
-
|
|
122
|
+
for (const spec of servers) {
|
|
123
|
+
if (disabled.has(`${key}/${spec.key}`))
|
|
124
|
+
continue;
|
|
125
|
+
const serverConfig = expandLspServerConfig(toLspServerConfig(spec), context);
|
|
126
|
+
config[`${key}/${spec.key}`] = await this.resolveServerCommand(serverConfig, spec.key, facts, pathExtensions);
|
|
127
|
+
}
|
|
121
128
|
if (Object.keys(config).length > 0)
|
|
122
|
-
wanted.set(key, { suite, config });
|
|
129
|
+
wanted.set(key, { suite, config, facts, pathExtensions });
|
|
123
130
|
}
|
|
124
131
|
// Direct user-configured servers ride the same mount path under the
|
|
125
132
|
// sentinel suite id, so their lifecycle (retries, diagnostics, disposal)
|
|
@@ -128,9 +135,13 @@ export class LspMountRegistry {
|
|
|
128
135
|
const directKeys = Object.keys(direct);
|
|
129
136
|
if (directKeys.length > 0) {
|
|
130
137
|
const config = {};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
138
|
+
const facts = [];
|
|
139
|
+
const pathExtensions = [];
|
|
140
|
+
for (const [key, spec] of Object.entries(direct)) {
|
|
141
|
+
if (disabled.has(`${DIRECT_LSP_SUITE_ID}/${key}`))
|
|
142
|
+
continue;
|
|
143
|
+
config[`${DIRECT_LSP_SUITE_ID}/${key}`] = await this.resolveServerCommand(toLspServerConfig(spec), key, facts, pathExtensions);
|
|
144
|
+
}
|
|
134
145
|
if (Object.keys(config).length > 0)
|
|
135
146
|
wanted.set(DIRECT_LSP_SUITE_ID, {
|
|
136
147
|
suite: {
|
|
@@ -147,7 +158,9 @@ export class LspMountRegistry {
|
|
|
147
158
|
activeSurfaces: effectiveSurfaces(undefined),
|
|
148
159
|
errors: []
|
|
149
160
|
},
|
|
150
|
-
config
|
|
161
|
+
config,
|
|
162
|
+
facts,
|
|
163
|
+
pathExtensions
|
|
151
164
|
});
|
|
152
165
|
}
|
|
153
166
|
// The last remaining server releases the capability seam; the first one mounts it.
|
|
@@ -168,9 +181,16 @@ export class LspMountRegistry {
|
|
|
168
181
|
this.lastDiagnostics.delete(key);
|
|
169
182
|
continue;
|
|
170
183
|
}
|
|
184
|
+
const causes = [...(capabilityFailure?.causes ?? []), ...entry.facts];
|
|
171
185
|
const failure = capabilityFailure === undefined
|
|
172
|
-
? await this.mountWith(key, entry.suite, entry.config)
|
|
173
|
-
: {
|
|
186
|
+
? await this.mountWith(key, entry.suite, entry.config, entry.facts, entry.pathExtensions)
|
|
187
|
+
: {
|
|
188
|
+
suiteId: key,
|
|
189
|
+
serverKey: Object.keys(entry.config).join(','),
|
|
190
|
+
reason: capabilityFailure.reason,
|
|
191
|
+
code: capabilityFailure.code,
|
|
192
|
+
...(causes.length === 0 ? {} : { causes })
|
|
193
|
+
};
|
|
174
194
|
if (failure !== undefined) {
|
|
175
195
|
diagnostics.push(failure);
|
|
176
196
|
this.lastDiagnostics.set(key, failure);
|
|
@@ -182,6 +202,30 @@ export class LspMountRegistry {
|
|
|
182
202
|
}
|
|
183
203
|
return diagnostics;
|
|
184
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Resolve one server's declared command, extending its `PATH` from the
|
|
207
|
+
* login shell only when the current environment cannot find the command.
|
|
208
|
+
*
|
|
209
|
+
* An explicit `env.PATH` is a declaration and is left verbatim; the command
|
|
210
|
+
* itself is never rewritten. A resolution fact (the extension, or the
|
|
211
|
+
* searched `PATH` when it still failed) is appended to the suite's facts so
|
|
212
|
+
* it reaches the mount diagnostic; a fact is also a PATH extension exactly
|
|
213
|
+
* when `resolution.path` is set, and rides `pathExtensions` for the trace log.
|
|
214
|
+
*/
|
|
215
|
+
async resolveServerCommand(config, serverKey, facts, pathExtensions) {
|
|
216
|
+
const resolution = await resolveDeclaredCommand(this.ctx, config.command, config.env ?? {});
|
|
217
|
+
if (resolution === undefined)
|
|
218
|
+
return config;
|
|
219
|
+
if (resolution.diagnostic !== undefined) {
|
|
220
|
+
const fact = `${serverKey}: ${resolution.diagnostic}`;
|
|
221
|
+
facts.push(fact);
|
|
222
|
+
if (resolution.path !== undefined)
|
|
223
|
+
pathExtensions.push(fact);
|
|
224
|
+
}
|
|
225
|
+
if (resolution.path === undefined)
|
|
226
|
+
return config;
|
|
227
|
+
return { ...config, env: { ...(config.env ?? {}), PATH: resolution.path } };
|
|
228
|
+
}
|
|
185
229
|
/**
|
|
186
230
|
* Mount the capability seam this plugin delivers end to end: `ctx.lsp`, then the model-facing
|
|
187
231
|
* `lsp` tool.
|
|
@@ -238,9 +282,9 @@ export class LspMountRegistry {
|
|
|
238
282
|
// `service "lsp" has been registered` / `tool "lsp" is already registered`: another layer
|
|
239
283
|
// owns the seam. Report the layer to drop rather than falling back to its version.
|
|
240
284
|
if (/already registered|has been registered/.test(message)) {
|
|
241
|
-
return { reason: await this.seamConflictReason(specifier, message), code: 'seam-conflict' };
|
|
285
|
+
return { reason: await this.seamConflictReason(specifier, message), code: 'seam-conflict', causes: causeMessages(error) };
|
|
242
286
|
}
|
|
243
|
-
return { reason: `mount failed: ${message}`, code: 'mount-failed' };
|
|
287
|
+
return { reason: `mount failed: ${message}`, code: 'mount-failed', causes: causeMessages(error) };
|
|
244
288
|
}
|
|
245
289
|
this.capability.push(handle);
|
|
246
290
|
return undefined;
|
|
@@ -297,7 +341,7 @@ export class LspMountRegistry {
|
|
|
297
341
|
return this.live.size > 0;
|
|
298
342
|
}
|
|
299
343
|
/** Mount one suite's full server table as a single `dsh-lsp-stdio` instance. */
|
|
300
|
-
async mountWith(key, suite, servers) {
|
|
344
|
+
async mountWith(key, suite, servers, facts = [], pathExtensions = []) {
|
|
301
345
|
const hostKeys = Object.keys(servers).join(',');
|
|
302
346
|
const module = await this.loadHost();
|
|
303
347
|
if (module === undefined) {
|
|
@@ -330,9 +374,14 @@ export class LspMountRegistry {
|
|
|
330
374
|
suiteId: key,
|
|
331
375
|
serverKey: hostKeys,
|
|
332
376
|
reason: `mount failed: ${message}`,
|
|
333
|
-
code: conflict ? 'seam-conflict' : 'mount-failed'
|
|
377
|
+
code: conflict ? 'seam-conflict' : 'mount-failed',
|
|
378
|
+
causes: [...causeMessages(error), ...facts]
|
|
334
379
|
};
|
|
335
380
|
}
|
|
381
|
+
// The mount is live: only a genuine PATH extension is worth a trace, and
|
|
382
|
+
// resolveServerCommand already marked those facts structurally.
|
|
383
|
+
for (const fact of pathExtensions)
|
|
384
|
+
this.ctx.logger?.info?.(`[dsh-agent-plugins-market] ${key}: ${fact}`);
|
|
336
385
|
this.live.set(key, { fingerprint: JSON.stringify(servers), suiteId: key, serverKeys: Object.keys(servers), disposer: () => handle.dispose() });
|
|
337
386
|
return undefined;
|
|
338
387
|
}
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
* @module runtime/mcp-client/bridge
|
|
21
21
|
*/
|
|
22
22
|
import { resolveReconnectPolicy, startConnection } from './connection.js';
|
|
23
|
-
import { validateConfig } from '
|
|
23
|
+
import { validateConfig } from '../../../application/mcp/mcp-bridge-config.js';
|
|
24
|
+
import { resolveDeclaredCommand } from '../../host/shell-path.js';
|
|
25
|
+
import { optionalService } from '../../core/context.js';
|
|
24
26
|
/** Cordis plugin name used by loader diagnostics. */
|
|
25
27
|
export const name = 'market-mcp-client';
|
|
26
28
|
/** Services required by this plugin. */
|
|
@@ -33,19 +35,6 @@ export const inject = ['tools'];
|
|
|
33
35
|
* defense for direct programmatic loads.
|
|
34
36
|
*/
|
|
35
37
|
const activeServerNames = new WeakMap();
|
|
36
|
-
/** Tolerantly read an optional service from the cordis context. */
|
|
37
|
-
function optionalService(ctx, serviceName) {
|
|
38
|
-
try {
|
|
39
|
-
const reader = ctx;
|
|
40
|
-
const service = reader.get?.(serviceName);
|
|
41
|
-
// A missing service either reads as undefined or throws (cordis strict
|
|
42
|
-
// mode); both mean "not mounted".
|
|
43
|
-
return service === null ? undefined : service;
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return undefined;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
38
|
/** Adapt the cordis context onto the structural host the bridge modules use. */
|
|
50
39
|
function toToolHost(ctx) {
|
|
51
40
|
const logger = {
|
|
@@ -74,6 +63,32 @@ function toToolHost(ctx) {
|
|
|
74
63
|
getService: serviceName => optionalService(ctx, serviceName)
|
|
75
64
|
};
|
|
76
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve one stdio command before the SDK spawns it, extending the child
|
|
68
|
+
* `PATH` from the login shell only when the current environment cannot find
|
|
69
|
+
* the command.
|
|
70
|
+
*
|
|
71
|
+
* An explicit `env.PATH` is the author's or user's declaration and is never
|
|
72
|
+
* touched: the bridge respects it verbatim and does not even probe. Without
|
|
73
|
+
* one, the child inherits the scrubbed parent `PATH`; when that cannot resolve
|
|
74
|
+
* the command (the desktop case, where `npx` is absent) the login shell's
|
|
75
|
+
* directories are appended, and the extension travels beside the config as
|
|
76
|
+
* `config.env.PATH`.
|
|
77
|
+
*
|
|
78
|
+
* Resolution never rejects: a command that stays unresolved keeps today's
|
|
79
|
+
* behavior (a spawn that fails with its own `ENOENT`), and the searched `PATH`
|
|
80
|
+
* is returned as a diagnostic so the failure can say what was tried.
|
|
81
|
+
*/
|
|
82
|
+
async function resolveStdioCommand(ctx, config) {
|
|
83
|
+
if (config.transport !== 'stdio')
|
|
84
|
+
return { config };
|
|
85
|
+
const resolution = await resolveDeclaredCommand(ctx, config.command, config.env);
|
|
86
|
+
if (resolution === undefined)
|
|
87
|
+
return { config };
|
|
88
|
+
const { path, diagnostic } = resolution;
|
|
89
|
+
const resolved = path === undefined ? config : { ...config, env: { ...config.env, PATH: path } };
|
|
90
|
+
return { config: resolved, ...(diagnostic === undefined ? {} : { diagnostic }) };
|
|
91
|
+
}
|
|
77
92
|
/**
|
|
78
93
|
* Connect one MCP server and publish its initial tool generation before
|
|
79
94
|
* activation. Remains explicitly `async`: Cordis treats a prototype-bearing
|
|
@@ -87,7 +102,9 @@ export async function apply(ctx, config) {
|
|
|
87
102
|
// Fail loud at load: programmatic construction bypasses any schema layer,
|
|
88
103
|
// so every invariant is re-judged here before any effect registers.
|
|
89
104
|
validateConfig(config);
|
|
90
|
-
const
|
|
105
|
+
const resolution = await resolveStdioCommand(ctx, config);
|
|
106
|
+
const resolvedConfig = resolution.config;
|
|
107
|
+
const reconnect = resolveReconnectPolicy(resolvedConfig.reconnect, `mcp-client(${resolvedConfig.serverName}): reconnect`);
|
|
91
108
|
// Reserve the namespace next: a duplicate `serverName` fails THIS instance
|
|
92
109
|
// at load with an actionable error and leaves the earlier instance intact.
|
|
93
110
|
ctx.effect(() => {
|
|
@@ -96,11 +113,11 @@ export async function apply(ctx, config) {
|
|
|
96
113
|
names = new Set();
|
|
97
114
|
activeServerNames.set(ctx.root, names);
|
|
98
115
|
}
|
|
99
|
-
if (names.has(
|
|
100
|
-
throw new Error(`market-mcp-client: serverName "${
|
|
116
|
+
if (names.has(resolvedConfig.serverName)) {
|
|
117
|
+
throw new Error(`market-mcp-client: serverName "${resolvedConfig.serverName}" is already in use by another bridge instance — pick a unique serverName`);
|
|
101
118
|
}
|
|
102
|
-
names.add(
|
|
103
|
-
return () => void names.delete(
|
|
119
|
+
names.add(resolvedConfig.serverName);
|
|
120
|
+
return () => void names.delete(resolvedConfig.serverName);
|
|
104
121
|
}, 'market-mcp-client.serverName');
|
|
105
122
|
// The supervisor owns the client/transport generations, the reconnect
|
|
106
123
|
// loop, and the live tool registrations; disposal stops reconnection,
|
|
@@ -110,7 +127,7 @@ export async function apply(ctx, config) {
|
|
|
110
127
|
// no-persistence configuration.
|
|
111
128
|
const host = toToolHost(ctx);
|
|
112
129
|
const credentials = optionalService(ctx, 'credentials');
|
|
113
|
-
const connection = startConnection(host,
|
|
130
|
+
const connection = startConnection(host, resolvedConfig, reconnect, credentials);
|
|
114
131
|
ctx.effect(() => {
|
|
115
132
|
return () => connection.dispose();
|
|
116
133
|
}, 'market-mcp-client.connection');
|
|
@@ -120,7 +137,20 @@ export async function apply(ctx, config) {
|
|
|
120
137
|
// fiber (Cordis rolls it back); otherwise the error is logged and the
|
|
121
138
|
// supervisor enters its reconnect loop.
|
|
122
139
|
const outcome = await connection.ready;
|
|
123
|
-
if (outcome.error !== undefined &&
|
|
124
|
-
|
|
140
|
+
if (outcome.error !== undefined && resolvedConfig.failOnStartupError) {
|
|
141
|
+
// The resolution fact explains why the spawn failed (or what was searched),
|
|
142
|
+
// so it rides the cause chain into the mount diagnostic ahead of the raw
|
|
143
|
+
// spawn error. On the happy path there is nothing to add and the chain is
|
|
144
|
+
// exactly today's.
|
|
145
|
+
const cause = resolution.diagnostic === undefined ? outcome.error : new Error(resolution.diagnostic, { cause: outcome.error });
|
|
146
|
+
throw new Error(`mcp-client(${resolvedConfig.serverName}): initial connection or tool synchronization failed`, { cause });
|
|
147
|
+
}
|
|
148
|
+
// A command that resolved only after the login shell extended PATH leaves a
|
|
149
|
+
// trace, so "why does this work now" is answerable from the log. With
|
|
150
|
+
// failOnStartupError=false a failed resolution reaches here too; the env.PATH
|
|
151
|
+
// guard excludes it, because PATH is only set on a successful extension —
|
|
152
|
+
// the transport check is the narrowing that makes env exist at all.
|
|
153
|
+
if (resolvedConfig.transport === 'stdio' && resolvedConfig.env.PATH !== undefined && resolution.diagnostic !== undefined) {
|
|
154
|
+
ctx.logger?.info?.(`market-mcp-client(${resolvedConfig.serverName}): ${resolution.diagnostic}`);
|
|
125
155
|
}
|
|
126
156
|
}
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
24
24
|
import { ToolListChangedNotificationSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
25
25
|
import { MAX_TIMER_DELAY_MS } from './host-seams.js';
|
|
26
|
-
import { redactErrorMessage } from '
|
|
26
|
+
import { redactErrorMessage } from '../../../application/mcp/mcp-redaction.js';
|
|
27
27
|
import { PLUGIN_NAME, PLUGIN_VERSION } from './plugin-identity.js';
|
|
28
28
|
import { createTransport } from './transport.js';
|
|
29
29
|
import { syncTools } from './tools.js';
|
|
30
|
-
import { DEFAULT_STARTUP_TIMEOUT_MS } from '
|
|
30
|
+
import { DEFAULT_STARTUP_TIMEOUT_MS } from '../../../application/mcp/mcp-bridge-config.js';
|
|
31
31
|
/** Defaults shared by the config and {@link resolveReconnectPolicy}. */
|
|
32
32
|
export const RECONNECT_DEFAULTS = Object.freeze({
|
|
33
33
|
enabled: true,
|
|
@@ -31,7 +31,7 @@ import { createServer } from 'node:http';
|
|
|
31
31
|
import { randomBytes } from 'node:crypto';
|
|
32
32
|
import { isDeepStrictEqual } from 'node:util';
|
|
33
33
|
import { credentialKey, scrubbedParentEnv } from './host-seams.js';
|
|
34
|
-
import { redactErrorMessage, redactUrl } from '
|
|
34
|
+
import { redactErrorMessage, redactUrl } from '../../../application/mcp/mcp-redaction.js';
|
|
35
35
|
import { PLUGIN_NAME, PLUGIN_VERSION } from './plugin-identity.js';
|
|
36
36
|
/** OAuth client identity presented during dynamic registration. */
|
|
37
37
|
const CLIENT_NAME = `DeepSeek Harness (${PLUGIN_NAME})`;
|
|
@@ -19,9 +19,9 @@ import { createHash } from 'node:crypto';
|
|
|
19
19
|
import { isDeepStrictEqual } from 'node:util';
|
|
20
20
|
import { ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
21
21
|
import { z } from 'zod';
|
|
22
|
-
import { assertSupportedJsonSchema } from '
|
|
22
|
+
import { assertSupportedJsonSchema } from '@deepseek-ai/dsh-tools';
|
|
23
23
|
import { containsImage, extractText, prepareImageProjection } from './projection.js';
|
|
24
|
-
import { redactErrorMessage } from '
|
|
24
|
+
import { redactErrorMessage } from '../../../application/mcp/mcp-redaction.js';
|
|
25
25
|
/**
|
|
26
26
|
* DeepSeek function-name contract: at most 64 characters. Wire-protocol
|
|
27
27
|
* constant, not configuration.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @module runtime/mcp-auth-record
|
|
10
10
|
*/
|
|
11
|
-
import { credentialKey } from './
|
|
11
|
+
import { credentialKey } from './bridge/host-seams.js';
|
|
12
12
|
/** Credential-record scope for MCP OAuth state; per-server ids follow it. */
|
|
13
13
|
export const MCP_AUTH_RECORD_SCOPE = 'mcp-auth';
|
|
14
14
|
/**
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { mkdir } from 'node:fs/promises';
|
|
3
|
-
import * as mcpBridge from './
|
|
4
|
-
import { toMcpMounts } from '
|
|
3
|
+
import * as mcpBridge from './bridge/bridge.js';
|
|
4
|
+
import { toMcpMounts } from '../../application/mcp/mcp-config.js';
|
|
5
5
|
import { mcpCredentialResolver } from './mcp-credentials.js';
|
|
6
|
-
import { SerialPassQueue, RetryScheduler } from '
|
|
7
|
-
import { qualifiedSuiteId, suiteDataDir } from '
|
|
8
|
-
import { redactErrorMessage } from '
|
|
6
|
+
import { SerialPassQueue, RetryScheduler } from '../core/mount-lifecycle.js';
|
|
7
|
+
import { qualifiedSuiteId, suiteDataDir } from '../../catalog/paths.js';
|
|
8
|
+
import { redactErrorMessage } from '../../application/mcp/mcp-redaction.js';
|
|
9
|
+
import { causeMessages } from '../host/failure-detail.js';
|
|
9
10
|
export class McpMountRegistry {
|
|
10
11
|
ctx;
|
|
11
12
|
pluginDataRoot;
|
|
@@ -157,7 +158,13 @@ export class McpMountRegistry {
|
|
|
157
158
|
// reported so a transient error does not shadow the final state.
|
|
158
159
|
const failure = await this.mountWith(entry.request);
|
|
159
160
|
if (failure !== undefined) {
|
|
160
|
-
diagnostics.push({
|
|
161
|
+
diagnostics.push({
|
|
162
|
+
suiteId: qualifiedSuiteId(entry.suite.sourceId, entry.suite.id),
|
|
163
|
+
serverKey: entry.serverKey,
|
|
164
|
+
reason: failure.reason,
|
|
165
|
+
code: failure.code,
|
|
166
|
+
...(failure.causes === undefined || failure.causes.length === 0 ? {} : { causes: failure.causes })
|
|
167
|
+
});
|
|
161
168
|
// Foreign and duplicate skips are deterministic, not transient:
|
|
162
169
|
// retrying them just burns the attempt budget and log lines. The
|
|
163
170
|
// next full reconcile re-checks them anyway, so the self-heal path
|
|
@@ -263,7 +270,7 @@ export class McpMountRegistry {
|
|
|
263
270
|
// Ignore teardown errors: the startup failure is the real signal.
|
|
264
271
|
}
|
|
265
272
|
}
|
|
266
|
-
return { reason: `mount failed: ${redactErrorMessage(error instanceof Error ? error.message : String(error))}`, code: 'mount-failed' };
|
|
273
|
+
return { reason: `mount failed: ${redactErrorMessage(error instanceof Error ? error.message : String(error))}`, code: 'mount-failed', causes: causeMessages(error) };
|
|
267
274
|
}
|
|
268
275
|
this.live.set(mountKey(request.suiteId, request.serverKey), {
|
|
269
276
|
suiteId: request.suiteId,
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* @module runtime/user-commands
|
|
11
11
|
*/
|
|
12
12
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
13
|
-
import { commandCallName } from '
|
|
14
|
-
import { USER_ENTRY_PATH } from '
|
|
15
|
-
import { pluginMarketSource } from '
|
|
13
|
+
import { commandCallName } from '../../model/command-names.js';
|
|
14
|
+
import { USER_ENTRY_PATH } from '../../application/panels/user-store.js';
|
|
15
|
+
import { pluginMarketSource } from '../host/plugin-message-source.js';
|
|
16
16
|
/** Register/unregister user-panel commands to match the panel's enabled entries. */
|
|
17
17
|
export class UserCommandMountRegistry {
|
|
18
18
|
ctx;
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
* @module runtime/user-panels
|
|
31
31
|
*/
|
|
32
32
|
import { dirname } from 'node:path';
|
|
33
|
-
import { skillEntryRejection } from '
|
|
34
|
-
import { deleteEntryDocument, entryExists, listEntryDocuments, listEntryFiles, readEntryDocument, resolveEntryDocument, SKILL_ENTRY_SHAPES, USER_ENTRY_NAME, USER_ENTRY_PATH, userEntryDir, writeEntryDocument, writeEntryFile } from '
|
|
33
|
+
import { skillEntryRejection } from '../../catalog/skills-parse.js';
|
|
34
|
+
import { deleteEntryDocument, entryExists, listEntryDocuments, listEntryFiles, readEntryDocument, resolveEntryDocument, SKILL_ENTRY_SHAPES, USER_ENTRY_NAME, USER_ENTRY_PATH, userEntryDir, writeEntryDocument, writeEntryFile } from '../../application/panels/user-store.js';
|
|
35
35
|
/** The skill-source label user-panel entries carry into the skill registry. */
|
|
36
36
|
export const USER_PANEL_SKILL_SOURCE = 'user-panel';
|
|
37
37
|
/**
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
2
2
|
import { parse as parseYaml } from 'yaml';
|
|
3
|
-
import { stripFrontmatter } from '
|
|
4
|
-
import { parseFrontmatterRecord } from '
|
|
5
|
-
import { qualifiedSuiteId, suiteDataDir } from '
|
|
6
|
-
import { expandPluginPaths, pluginRootOf } from '
|
|
7
|
-
import { defaultMarkdownResources, resourceText, resourceCommandName } from '
|
|
8
|
-
import { bindHostLocale } from '
|
|
3
|
+
import { stripFrontmatter } from '../../catalog/skills-parse.js';
|
|
4
|
+
import { parseFrontmatterRecord } from '../../application/panels/user-store.js';
|
|
5
|
+
import { qualifiedSuiteId, suiteDataDir } from '../../catalog/paths.js';
|
|
6
|
+
import { expandPluginPaths, pluginRootOf } from '../../catalog/plugin-variables.js';
|
|
7
|
+
import { defaultMarkdownResources, resourceText, resourceCommandName } from '../../catalog/component-files.js';
|
|
8
|
+
import { bindHostLocale } from '../host/host-locale.js';
|
|
9
9
|
import { injectDynamicContext, shellSeamOf } from './dynamic-context.js';
|
|
10
|
-
import { pluginMarketSource } from '
|
|
10
|
+
import { pluginMarketSource } from '../host/plugin-message-source.js';
|
|
11
11
|
const COMMAND_NAME = /^[a-z][a-z0-9_-]*$/;
|
|
12
12
|
export class CommandMountRegistry {
|
|
13
13
|
ctx;
|
|
@@ -18,8 +18,8 @@ import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write';
|
|
|
18
18
|
import { tmpdir } from 'node:os';
|
|
19
19
|
import { createHash } from 'node:crypto';
|
|
20
20
|
import { join } from 'node:path';
|
|
21
|
-
import { SerialPassQueue } from '
|
|
22
|
-
import { qualifiedSuiteId } from '
|
|
21
|
+
import { SerialPassQueue } from '../core/mount-lifecycle.js';
|
|
22
|
+
import { qualifiedSuiteId } from '../../catalog/paths.js';
|
|
23
23
|
export class HooksMountRegistry {
|
|
24
24
|
ctx;
|
|
25
25
|
live = new Map();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CommandMountRegistry } from './commands-mounts.js';
|
|
2
|
-
import { expandPluginPaths, pluginRootOf } from '
|
|
3
|
-
import { suiteDataDir } from '
|
|
4
|
-
import { McpMountRegistry } from '
|
|
2
|
+
import { expandPluginPaths, pluginRootOf } from '../../catalog/plugin-variables.js';
|
|
3
|
+
import { suiteDataDir } from '../../catalog/paths.js';
|
|
4
|
+
import { McpMountRegistry } from '../mcp/mcp-mounts.js';
|
|
5
5
|
import { HooksMountRegistry } from './hooks-mounts.js';
|
|
6
6
|
import { readFile } from 'node:fs/promises';
|
|
7
|
-
import { stripFrontmatter } from '
|
|
8
|
-
import { parseFrontmatterRecord } from '
|
|
7
|
+
import { stripFrontmatter } from '../../catalog/skills-parse.js';
|
|
8
|
+
import { parseFrontmatterRecord } from '../../application/panels/user-store.js';
|
|
9
9
|
/** Mount under existing and newly created agents; the caller owns refresh and teardown. */
|
|
10
10
|
export function mountProjectCommands(ctx, catalog, t, dataRoot) {
|
|
11
11
|
return mountProjectSurface(ctx, catalog, 'commands', scope => new CommandMountRegistry(scope, t, dataRoot));
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
* directory, so CC-authored skills work verbatim under the harness.
|
|
15
15
|
*/
|
|
16
16
|
import { readFile } from 'node:fs/promises';
|
|
17
|
-
import { parseSkillFrontmatter, stripFrontmatter } from '
|
|
18
|
-
import { parseFrontmatterRecord } from '
|
|
19
|
-
import { expandPluginPaths, pluginRootOf } from '
|
|
20
|
-
import { suiteDataDir } from '
|
|
17
|
+
import { parseSkillFrontmatter, stripFrontmatter } from '../../catalog/skills-parse.js';
|
|
18
|
+
import { parseFrontmatterRecord } from '../../application/panels/user-store.js';
|
|
19
|
+
import { expandPluginPaths, pluginRootOf } from '../../catalog/plugin-variables.js';
|
|
20
|
+
import { suiteDataDir } from '../../catalog/paths.js';
|
|
21
21
|
import { injectDynamicContext } from './dynamic-context.js';
|
|
22
22
|
export const SUITE_PROJECT_SOURCE = 'agent-plugin-project';
|
|
23
23
|
export const SUITE_USER_SOURCE = 'agent-plugin-user';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panel identity is preserved so identically named cards from different suites remain addressable.
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentRoleEntry {
|
|
5
|
+
name: string;
|
|
6
|
+
path: string;
|
|
7
|
+
description: string;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
title?: string;
|
|
10
|
+
rawText?: string;
|
|
11
|
+
/** Suite checkout root the card's `${PLUGIN_ROOT}` variables resolve to; absent for project-native files. */
|
|
12
|
+
suiteRoot?: string;
|
|
13
|
+
/** The suite's `${PLUGIN_DATA}` directory; absent for project-native files. */
|
|
14
|
+
suiteData?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The executable part of one card. `tools` / `disallowedTools` stay in the file
|
|
18
|
+
* and are preserved by the editors, but they are not applied.
|
|
19
|
+
*/
|
|
20
|
+
export interface AgentRolePolicy {
|
|
21
|
+
content: string;
|
|
22
|
+
model?: string;
|
|
23
|
+
provider?: string;
|
|
24
|
+
reasoningEffort?: string;
|
|
25
|
+
title?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
disabled: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** Strict YAML parsing prevents malformed routing metadata from silently inheriting wider privileges. */
|
|
30
|
+
export declare function parseAgentRole(text: string): AgentRolePolicy;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { LspLegacySeamMigration, LspStatusPayload } from '../contracts/lsp-status.js';
|
|
2
2
|
import type { OverviewPayload, ServerConfigPayload, SkillContent, SourceProgress, SuiteDetail } from '../contracts/market.js';
|
|
3
|
-
import type { McpStatusPayload } from '
|
|
3
|
+
import type { McpStatusPayload } from './mcp/mcp-status.js';
|
|
4
4
|
import type { SourceRef, Suite, SuiteSurfaceKey } from '../model/types.js';
|
|
5
|
-
import type { McpBackend } from '../
|
|
6
|
-
import {
|
|
7
|
-
import type
|
|
8
|
-
import { type McpServerOverride, type McpSuiteOverrides } from '../runtime/mcp-overrides.js';
|
|
5
|
+
import type { McpBackend } from '../contracts/mcp.js';
|
|
6
|
+
import type { McpMountDiagnostic } from '../contracts/mcp.js';
|
|
7
|
+
import { type McpServerOverride, type McpSuiteOverrides } from './mcp/mcp-overrides.js';
|
|
9
8
|
import { type CatalogGitOptions, type CatalogOptions } from './catalog-context.js';
|
|
10
9
|
import { type LspServerTable, type McpBackendInfo, type SourceInput, type SourcePatch } from './ports.js';
|
|
11
10
|
import { type CatalogSnapshot } from './snapshot-cache.js';
|
|
@@ -95,8 +94,6 @@ export declare class Catalog implements MarketService {
|
|
|
95
94
|
mcpStatus(): Promise<McpStatusPayload>;
|
|
96
95
|
/** Persist a user-owned MCP service and reconcile its bridge mount. */
|
|
97
96
|
addMcpServer(name: string, server: unknown): Promise<void>;
|
|
98
|
-
/** Import several pasted services in one write; each entry reports its own outcome. */
|
|
99
|
-
importMcpServers(servers: unknown, overwrite: boolean): Promise<McpImportResult>;
|
|
100
97
|
/** Read effective service configuration without exposing credential literals. */
|
|
101
98
|
serverConfig(kind: 'mcp' | 'lsp', id: string): Promise<ServerConfigPayload>;
|
|
102
99
|
/** Validate a complete replacement before writing; plugin checkouts remain untouched. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SkillContent, SuiteDetail } from '../contracts/market.js';
|
|
2
2
|
import { type InstalledEntry, type Suite } from '../model/types.js';
|
|
3
|
-
import type { McpMountDiagnostic as McpDiagnostic } from '../
|
|
3
|
+
import type { McpMountDiagnostic as McpDiagnostic } from '../contracts/mcp.js';
|
|
4
4
|
/** Build the detail response for one normalized suite. */
|
|
5
5
|
export declare function buildSuiteDetail(suite: Suite, installed: InstalledEntry | undefined, diagnostics: readonly McpDiagnostic[], mcpOverrides?: Record<string, Record<string, unknown>>): Promise<SuiteDetail>;
|
|
6
6
|
/** Read one skill body from a normalized suite. */
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read one JSON document. Resolves `undefined` when the file is absent or its
|
|
3
|
+
* text is empty; a `parse` that wants an absent file to read as a default
|
|
4
|
+
* handles `undefined` itself.
|
|
5
|
+
*/
|
|
6
|
+
export declare function readJsonFile(path: string): Promise<unknown>;
|
|
7
|
+
/**
|
|
8
|
+
* Write one JSON document atomically: two-space indent, trailing newline, and
|
|
9
|
+
* the private-file modes the plugin's state files carry (0o600 file, 0o700
|
|
10
|
+
* directory).
|
|
11
|
+
*/
|
|
12
|
+
export declare function writeJsonDocument(path: string, document: unknown): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LspServerSpec } from '
|
|
1
|
+
import type { LspServerSpec } from '../../model/types.js';
|
|
2
2
|
/** The direct LSP server configuration file path. */
|
|
3
3
|
export declare function lspServersPath(agentsRoot: string): string;
|
|
4
4
|
/** Load the user-configured LSP servers; unreadable or invalid files yield an empty table. */
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* Direct user-configured rows follow the same model under the sentinel suite
|
|
13
13
|
* id `direct` (mirroring mcp-status's `plugin`/`direct` split).
|
|
14
14
|
*/
|
|
15
|
-
import type { LspStatusPayload } from '
|
|
16
|
-
import type { LspMountDiagnostic } from '
|
|
17
|
-
import type { LspServerSpec, Suite } from '
|
|
15
|
+
import type { LspStatusPayload } from '../../contracts/lsp-status.js';
|
|
16
|
+
import type { LspMountDiagnostic } from '../../contracts/lsp.js';
|
|
17
|
+
import type { LspServerSpec, Suite } from '../../model/types.js';
|
|
18
18
|
/** Sentinel suite id for user-configured (non-suite) LSP servers. */
|
|
19
19
|
export declare const DIRECT_LSP_SUITE_ID = "direct";
|
|
20
20
|
/** The subset of LspMountRegistry the aggregator consumes (structural, for tests). */
|