@agentxm/extension-materialization 0.28.14-preview.1789139351.5cd4595aa
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +110 -0
- package/README.md +16 -0
- package/dist/src/desired-state/errors.d.ts +22 -0
- package/dist/src/desired-state/errors.js +22 -0
- package/dist/src/desired-state/retained-materialization.d.ts +58 -0
- package/dist/src/desired-state/retained-materialization.js +119 -0
- package/dist/src/errors.d.ts +42 -0
- package/dist/src/errors.js +14 -0
- package/dist/src/extensions/canonical-directory.d.ts +106 -0
- package/dist/src/extensions/canonical-directory.js +210 -0
- package/dist/src/extensions/canonical-reuse.d.ts +43 -0
- package/dist/src/extensions/canonical-reuse.js +38 -0
- package/dist/src/extensions/copy-directory.d.ts +50 -0
- package/dist/src/extensions/copy-directory.js +78 -0
- package/dist/src/extensions/errors.d.ts +97 -0
- package/dist/src/extensions/errors.js +42 -0
- package/dist/src/extensions/materializable-from-disk.d.ts +37 -0
- package/dist/src/extensions/materializable-from-disk.js +89 -0
- package/dist/src/extensions/operations.d.ts +252 -0
- package/dist/src/extensions/operations.js +631 -0
- package/dist/src/hooks/errors.d.ts +33 -0
- package/dist/src/hooks/errors.js +18 -0
- package/dist/src/hooks/manager.d.ts +13 -0
- package/dist/src/hooks/manager.js +778 -0
- package/dist/src/index.d.ts +44 -0
- package/dist/src/index.js +56 -0
- package/dist/src/knowledge/errors.d.ts +75 -0
- package/dist/src/knowledge/errors.js +36 -0
- package/dist/src/knowledge/manager.d.ts +9 -0
- package/dist/src/knowledge/manager.js +709 -0
- package/dist/src/live.d.ts +20 -0
- package/dist/src/live.js +20 -0
- package/dist/src/manager-contract.d.ts +136 -0
- package/dist/src/manager-contract.js +19 -0
- package/dist/src/manager-registry-live.d.ts +11 -0
- package/dist/src/manager-registry-live.js +23 -0
- package/dist/src/manager-registry.d.ts +37 -0
- package/dist/src/manager-registry.js +22 -0
- package/dist/src/managers.d.ts +147 -0
- package/dist/src/managers.js +32 -0
- package/dist/src/mcps/artifact.d.ts +24 -0
- package/dist/src/mcps/artifact.js +74 -0
- package/dist/src/mcps/authored-materialization.d.ts +28 -0
- package/dist/src/mcps/authored-materialization.js +34 -0
- package/dist/src/mcps/errors.d.ts +105 -0
- package/dist/src/mcps/errors.js +40 -0
- package/dist/src/mcps/install-operation.d.ts +92 -0
- package/dist/src/mcps/install-operation.js +557 -0
- package/dist/src/mcps/manager.d.ts +15 -0
- package/dist/src/mcps/manager.js +253 -0
- package/dist/src/mcps/native-entry.d.ts +51 -0
- package/dist/src/mcps/native-entry.js +100 -0
- package/dist/src/mcps/secret-store-live.d.ts +14 -0
- package/dist/src/mcps/secret-store-live.js +58 -0
- package/dist/src/mcps/secret-store.d.ts +55 -0
- package/dist/src/mcps/secret-store.js +33 -0
- package/dist/src/packs/errors.d.ts +50 -0
- package/dist/src/packs/errors.js +24 -0
- package/dist/src/packs/manager.d.ts +16 -0
- package/dist/src/packs/manager.js +189 -0
- package/dist/src/projection-participants-live.d.ts +17 -0
- package/dist/src/projection-participants-live.js +66 -0
- package/dist/src/projection-step-failure.d.ts +19 -0
- package/dist/src/projection-step-failure.js +76 -0
- package/dist/src/registry-materialization.d.ts +52 -0
- package/dist/src/registry-materialization.js +67 -0
- package/dist/src/rules/errors.d.ts +31 -0
- package/dist/src/rules/errors.js +17 -0
- package/dist/src/rules/manager.d.ts +18 -0
- package/dist/src/rules/manager.js +492 -0
- package/dist/src/skills/errors.d.ts +42 -0
- package/dist/src/skills/errors.js +21 -0
- package/dist/src/skills/manager.d.ts +17 -0
- package/dist/src/skills/manager.js +339 -0
- package/dist/src/skills/materialization.d.ts +52 -0
- package/dist/src/skills/materialization.js +168 -0
- package/dist/src/skills/skill-artifact.d.ts +38 -0
- package/dist/src/skills/skill-artifact.js +70 -0
- package/dist/src/skills/source-hash.d.ts +2 -0
- package/dist/src/skills/source-hash.js +6 -0
- package/dist/src/subagents/errors.d.ts +43 -0
- package/dist/src/subagents/errors.js +20 -0
- package/dist/src/subagents/lock-entry-builder.d.ts +20 -0
- package/dist/src/subagents/lock-entry-builder.js +63 -0
- package/dist/src/subagents/manager.d.ts +17 -0
- package/dist/src/subagents/manager.js +736 -0
- package/dist/src/testing.d.ts +87 -0
- package/dist/src/testing.js +116 -0
- package/package.json +70 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server extension manager service.
|
|
3
|
+
*
|
|
4
|
+
* Implements ExtensionManager<McpServerExtensionRef>. Delegates to existing
|
|
5
|
+
* MCP server materialization functions and workspace service methods.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
import * as FileSystem from "effect/FileSystem";
|
|
10
|
+
import * as Path from "effect/Path";
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Layer from "effect/Layer";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import { McpInstallStateMissing, McpRegistryOnlyInstall } from "./errors.js";
|
|
15
|
+
import { applyProjectionPlans, planSingletonProjection } from "@agentxm/workspace-projection";
|
|
16
|
+
import { McpConfigIoFailed, removeMcpServerFromManifest } from "@agentxm/agent-integration";
|
|
17
|
+
import { NO_MATERIALIZATION_OBSERVATION } from "../manager-contract.js";
|
|
18
|
+
import { McpServerManager } from "../managers.js";
|
|
19
|
+
import { configuredMcpServersToDiskRefs } from "../extensions/materializable-from-disk.js";
|
|
20
|
+
import { mcpRegistryResolutionKey, WorkspaceMutations } from "@agentxm/workspace-state";
|
|
21
|
+
import { canReuseInstalledPackage } from "../extensions/canonical-directory.js";
|
|
22
|
+
import { materializeRegistryPackageWithTreeIntegrity } from "../registry-materialization.js";
|
|
23
|
+
import { computeExtensionPathsForLayout } from "@agentxm/workspace-state";
|
|
24
|
+
import { acceptedRegistryVersionForRef, validateExactResolvedVersion, } from "@agentxm/workspace-state";
|
|
25
|
+
import { decodeVersionSync } from "@agentxm/extension-model/unstable/version-constraints";
|
|
26
|
+
import { configuredRowsByName } from "@agentxm/workspace-state";
|
|
27
|
+
import { isObservedInstalled } from "@agentxm/workspace-state";
|
|
28
|
+
import { acceptedCanonicalObservation, prepareAcceptedCanonicalTransition, removableAcceptedCanonicalPath, } from "@agentxm/workspace-state";
|
|
29
|
+
import { protectWorkspacePath } from "@agentxm/workspace-transactions";
|
|
30
|
+
import { computeMaterializedTreeIntegrity } from "@agentxm/workspace-state";
|
|
31
|
+
// Build lock entry from registry ref
|
|
32
|
+
const buildMcpServerLockEntry = (ref, treeIntegrity) => ({
|
|
33
|
+
type: "registry",
|
|
34
|
+
sourceType: "registry",
|
|
35
|
+
packageFormat: "agentxm",
|
|
36
|
+
endpoint: ref.source.location,
|
|
37
|
+
extensionType: "mcp-server",
|
|
38
|
+
workspaceName: ref.server.name,
|
|
39
|
+
owner: ref.owner,
|
|
40
|
+
name: ref.name,
|
|
41
|
+
resolvedVersion: decodeVersionSync(ref.version),
|
|
42
|
+
integrity: Option.getOrElse(ref.integrity, () => ""),
|
|
43
|
+
sourceName: ref.source.name,
|
|
44
|
+
publisherBindingId: ref.publisherBindingId,
|
|
45
|
+
treeIntegrity,
|
|
46
|
+
});
|
|
47
|
+
// -----------------------------------------------------------------------------
|
|
48
|
+
// Live Layer
|
|
49
|
+
// -----------------------------------------------------------------------------
|
|
50
|
+
export const McpServerManagerLive = Layer.effect(McpServerManager, Effect.gen(function* () {
|
|
51
|
+
const ws = yield* WorkspaceMutations;
|
|
52
|
+
const fs = yield* FileSystem.FileSystem;
|
|
53
|
+
const path = yield* Path.Path;
|
|
54
|
+
const baseDir = ws.baseDir;
|
|
55
|
+
const acquired = (treeIntegrity) => ({
|
|
56
|
+
observation: NO_MATERIALIZATION_OBSERVATION,
|
|
57
|
+
treeIntegrity,
|
|
58
|
+
removal: Option.none(),
|
|
59
|
+
});
|
|
60
|
+
const materializeInstall = Effect.fn("McpServerManager.materializeInstall")(function* ({ ref, force, }) {
|
|
61
|
+
if (ref.refType !== "registry") {
|
|
62
|
+
return yield* new McpRegistryOnlyInstall({
|
|
63
|
+
serverName: ref.server.name,
|
|
64
|
+
refType: ref.refType,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const registryRef = ref;
|
|
68
|
+
const canonicalPath = computeExtensionPathsForLayout(path.join, ws.layout, registryRef, "mcps", registryRef.name).canonicalPath;
|
|
69
|
+
const lockedEntry = yield* ws.getLockedMcpServer(mcpRegistryResolutionKey({
|
|
70
|
+
authority: registryRef.source.location,
|
|
71
|
+
owner: registryRef.owner,
|
|
72
|
+
name: registryRef.server.name,
|
|
73
|
+
}));
|
|
74
|
+
const lockedVersion = acceptedRegistryVersionForRef(lockedEntry, registryRef);
|
|
75
|
+
const useExisting = yield* canReuseInstalledPackage({
|
|
76
|
+
installedPath: canonicalPath,
|
|
77
|
+
force: force === true,
|
|
78
|
+
refVersion: registryRef.version,
|
|
79
|
+
hasIntegrity: Option.isSome(registryRef.integrity),
|
|
80
|
+
...(lockedVersion === undefined ? {} : { lockedVersion }),
|
|
81
|
+
existsFailureDetail: (target) => `Failed to check if canonical path exists: ${target}`,
|
|
82
|
+
});
|
|
83
|
+
if (useExisting && Option.isSome(lockedEntry)) {
|
|
84
|
+
const observedTree = yield* computeMaterializedTreeIntegrity(canonicalPath);
|
|
85
|
+
if (observedTree === lockedEntry.value.treeIntegrity) {
|
|
86
|
+
return acquired(Option.some(lockedEntry.value.treeIntegrity));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const materialized = yield* materializeRegistryPackageWithTreeIntegrity({
|
|
90
|
+
baseDir,
|
|
91
|
+
destinationPath: canonicalPath,
|
|
92
|
+
sourceLocation: registryRef.source.location,
|
|
93
|
+
owner: registryRef.owner,
|
|
94
|
+
type: "mcp-server",
|
|
95
|
+
name: registryRef.name,
|
|
96
|
+
version: registryRef.version,
|
|
97
|
+
integrity: registryRef.integrity,
|
|
98
|
+
messages: {
|
|
99
|
+
integrityMismatchDetail: `Integrity mismatch for ${registryRef.name}@${registryRef.version}`,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
return acquired(Option.some(materialized.treeIntegrity));
|
|
103
|
+
});
|
|
104
|
+
const makeMaterializeRemoval = (retainCanonical) => Effect.fn("McpServerManager.materializeRemoval")(function* ({ target }) {
|
|
105
|
+
const graph = yield* ws.getDesiredStateGraph();
|
|
106
|
+
const desiredNode = graph.nodes.find((node) => node.type === "mcp-server" && node.name === target.name);
|
|
107
|
+
const closure = desiredNode === undefined || desiredNode.authority === "inline"
|
|
108
|
+
? undefined
|
|
109
|
+
: graph.mcpSourceClosures.find((candidate) => candidate.identity === desiredNode.identity);
|
|
110
|
+
const retainShared = closure !== undefined && closure.localNames.some((name) => name !== target.name);
|
|
111
|
+
const withdrawn = {
|
|
112
|
+
observation: NO_MATERIALIZATION_OBSERVATION,
|
|
113
|
+
treeIntegrity: Option.none(),
|
|
114
|
+
removal: Option.some({
|
|
115
|
+
resolutionKey: desiredNode === undefined || desiredNode.authority === "inline"
|
|
116
|
+
? Option.none()
|
|
117
|
+
: Option.some(desiredNode.identity),
|
|
118
|
+
retainShared,
|
|
119
|
+
}),
|
|
120
|
+
};
|
|
121
|
+
const configuredAgents = yield* ws.getConfiguredAgents();
|
|
122
|
+
yield* applyProjectionPlans(configuredAgents.map((agentId) => planSingletonProjection({
|
|
123
|
+
unitId: "mcp-server:native-config-entry",
|
|
124
|
+
// Multiple configured agents may share one native config file.
|
|
125
|
+
targetFile: `mcp:${target.name}:configured-agents`,
|
|
126
|
+
contributor: target,
|
|
127
|
+
adapter: {
|
|
128
|
+
observe: () => Effect.succeed({
|
|
129
|
+
unitId: "mcp-server:native-config-entry",
|
|
130
|
+
path: `${agentId}:${target.name}`,
|
|
131
|
+
present: true,
|
|
132
|
+
current: false,
|
|
133
|
+
expectedContributors: [],
|
|
134
|
+
observedContributors: [target.name],
|
|
135
|
+
}),
|
|
136
|
+
apply: () => removeMcpServerFromManifest(agentId, {
|
|
137
|
+
workspaceRoot: baseDir,
|
|
138
|
+
scope: ws.scope,
|
|
139
|
+
serverName: target.name,
|
|
140
|
+
}).pipe(Effect.asVoid),
|
|
141
|
+
},
|
|
142
|
+
})));
|
|
143
|
+
if (retainCanonical || retainShared)
|
|
144
|
+
return withdrawn;
|
|
145
|
+
const canonical = yield* acceptedCanonicalObservation({
|
|
146
|
+
workspace: ws,
|
|
147
|
+
type: "mcp-server",
|
|
148
|
+
name: target.name,
|
|
149
|
+
});
|
|
150
|
+
const serverPath = removableAcceptedCanonicalPath(canonical);
|
|
151
|
+
if (Option.isSome(serverPath)) {
|
|
152
|
+
yield* protectWorkspacePath(serverPath.value);
|
|
153
|
+
yield* fs.remove(serverPath.value, { recursive: true, force: true }).pipe(Effect.mapError((cause) => new McpConfigIoFailed({
|
|
154
|
+
detail: `Failed to remove MCP server package: ${serverPath.value}`,
|
|
155
|
+
cause,
|
|
156
|
+
})));
|
|
157
|
+
}
|
|
158
|
+
return withdrawn;
|
|
159
|
+
});
|
|
160
|
+
const materializeUninstall = makeMaterializeRemoval(false);
|
|
161
|
+
const materializeDeactivate = makeMaterializeRemoval(true);
|
|
162
|
+
return {
|
|
163
|
+
type: "mcp-server",
|
|
164
|
+
isInstalled: Effect.fn("McpServerManager.isInstalled")(function* ({ target, }) {
|
|
165
|
+
return yield* isObservedInstalled(ws, "mcp-server", target.name);
|
|
166
|
+
}),
|
|
167
|
+
materializeInstall,
|
|
168
|
+
prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
|
|
169
|
+
workspace: ws,
|
|
170
|
+
type: "mcp-server",
|
|
171
|
+
name: ref.server.name,
|
|
172
|
+
ref,
|
|
173
|
+
}),
|
|
174
|
+
getConfiguredSource: Effect.fn("McpServerManager.getConfiguredSource")(function* ({ target, }) {
|
|
175
|
+
const configured = yield* ws.getConfiguredMcpServerEntries();
|
|
176
|
+
return Option.fromUndefinedOr(configured[target.name]?.source);
|
|
177
|
+
}),
|
|
178
|
+
isConfigured: Effect.fn("McpServerManager.isConfigured")(function* ({ target }) {
|
|
179
|
+
const configured = yield* ws.getConfiguredMcpServerEntries();
|
|
180
|
+
return configured[target.name] !== undefined;
|
|
181
|
+
}),
|
|
182
|
+
listMaterializable: Effect.fn("McpServerManager.listMaterializable")(function* () {
|
|
183
|
+
const configured = yield* ws.records
|
|
184
|
+
.rows("mcp-server")
|
|
185
|
+
.pipe(Effect.map(configuredRowsByName));
|
|
186
|
+
return yield* configuredMcpServersToDiskRefs({ fs, path, baseDir, scope: ws.scope, layout: ws.layout }, configured);
|
|
187
|
+
}),
|
|
188
|
+
materializeUninstall,
|
|
189
|
+
materializeDeactivate,
|
|
190
|
+
upsertSettingsEntry: ({ ref, versionRange, materialization, }) => {
|
|
191
|
+
if (ref.refType !== "registry")
|
|
192
|
+
return Effect.void.pipe(Effect.withSpan("McpServerManager.upsertSettingsEntry"));
|
|
193
|
+
const registryRef = ref;
|
|
194
|
+
return validateExactResolvedVersion(`mcpServers.${ref.server.name}.resolvedVersion`, registryRef.version).pipe(Effect.flatMap(() => {
|
|
195
|
+
const treeIntegrity = materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity));
|
|
196
|
+
if (Option.isNone(treeIntegrity)) {
|
|
197
|
+
return Effect.fail(new McpInstallStateMissing({ name: registryRef.server.name }));
|
|
198
|
+
}
|
|
199
|
+
const lockEntry = buildMcpServerLockEntry(registryRef, treeIntegrity.value);
|
|
200
|
+
return ws.setMcpServer({
|
|
201
|
+
name: ref.server.name,
|
|
202
|
+
resolutionKey: mcpRegistryResolutionKey({
|
|
203
|
+
authority: registryRef.source.location,
|
|
204
|
+
owner: registryRef.owner,
|
|
205
|
+
name: registryRef.server.name,
|
|
206
|
+
}),
|
|
207
|
+
lockEntry,
|
|
208
|
+
versionRange,
|
|
209
|
+
});
|
|
210
|
+
}), Effect.withSpan("McpServerManager.upsertSettingsEntry"));
|
|
211
|
+
},
|
|
212
|
+
removeSettingsEntry: ({ target }) => ws
|
|
213
|
+
.removeMcpServerSettings(target.name)
|
|
214
|
+
.pipe(Effect.withSpan("McpServerManager.removeSettingsEntry")),
|
|
215
|
+
upsertLockfileEntry: ({ ref, materialization, }) => {
|
|
216
|
+
if (ref.refType !== "registry")
|
|
217
|
+
return ws
|
|
218
|
+
.removeMcpServerLock(ref.server.name)
|
|
219
|
+
.pipe(Effect.withSpan("McpServerManager.upsertLockfileEntry"));
|
|
220
|
+
const registryRef = ref;
|
|
221
|
+
return validateExactResolvedVersion(`mcpServers.${ref.server.name}.resolvedVersion`, registryRef.version).pipe(Effect.flatMap(() => {
|
|
222
|
+
const treeIntegrity = materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity));
|
|
223
|
+
if (Option.isNone(treeIntegrity)) {
|
|
224
|
+
return Effect.fail(new McpInstallStateMissing({ name: registryRef.server.name }));
|
|
225
|
+
}
|
|
226
|
+
const lockEntry = buildMcpServerLockEntry(registryRef, treeIntegrity.value);
|
|
227
|
+
return ws.setMcpServerLock({
|
|
228
|
+
name: ref.server.name,
|
|
229
|
+
resolutionKey: mcpRegistryResolutionKey({
|
|
230
|
+
authority: registryRef.source.location,
|
|
231
|
+
owner: registryRef.owner,
|
|
232
|
+
name: registryRef.server.name,
|
|
233
|
+
}),
|
|
234
|
+
lockEntry,
|
|
235
|
+
versionRange: Option.none(),
|
|
236
|
+
});
|
|
237
|
+
}), Effect.withSpan("McpServerManager.upsertLockfileEntry"));
|
|
238
|
+
},
|
|
239
|
+
removeLockfileEntry: ({ materialization, }) => {
|
|
240
|
+
const removal = materialization.pipe(Option.flatMap((facts) => facts.removal));
|
|
241
|
+
if (Option.isNone(removal)) {
|
|
242
|
+
return Effect.void.pipe(Effect.withSpan("McpServerManager.removeLockfileEntry"));
|
|
243
|
+
}
|
|
244
|
+
if (removal.value.retainShared || Option.isNone(removal.value.resolutionKey)) {
|
|
245
|
+
return Effect.void.pipe(Effect.withSpan("McpServerManager.removeLockfileEntry"));
|
|
246
|
+
}
|
|
247
|
+
return ws
|
|
248
|
+
.removeMcpServerLock(removal.value.resolutionKey.value)
|
|
249
|
+
.pipe(Effect.withSpan("McpServerManager.removeLockfileEntry"));
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
}));
|
|
253
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retiring a native MCP entry that a managed package now represents.
|
|
3
|
+
*
|
|
4
|
+
* Converting a native connection into an authored package leaves the original
|
|
5
|
+
* declaration in the agent's own config file. Removing it is the last step of
|
|
6
|
+
* that conversion and belongs inside the same transaction that publishes the
|
|
7
|
+
* package, so it lives in this capability beside `installMcpServer` rather
|
|
8
|
+
* than in the feature that discovered the native entry: the authoring routes
|
|
9
|
+
* that perform the conversion may not import a peer feature.
|
|
10
|
+
*
|
|
11
|
+
* The removal is conditional on the config still saying what it said when the
|
|
12
|
+
* conversion was planned. A native file that changed underneath is reported,
|
|
13
|
+
* never overwritten.
|
|
14
|
+
*
|
|
15
|
+
* @experimental This API is unstable and may change without notice.
|
|
16
|
+
*/
|
|
17
|
+
import * as Effect from "effect/Effect";
|
|
18
|
+
import * as FileSystem from "effect/FileSystem";
|
|
19
|
+
import * as Schema from "effect/Schema";
|
|
20
|
+
/** One native MCP declaration, addressed exactly as its config file holds it. */
|
|
21
|
+
export interface NativeMcpEntryRef {
|
|
22
|
+
/** Absolute path of the agent-native config file holding the declaration. */
|
|
23
|
+
readonly filePath: string;
|
|
24
|
+
/** Key under which that file collects its MCP servers. */
|
|
25
|
+
readonly serversKey: string;
|
|
26
|
+
/** The native connection key being retired. */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
}
|
|
29
|
+
declare const NativeMcpEntryRetirementFailed_base: Schema.Class<NativeMcpEntryRetirementFailed, Schema.TaggedStruct<"NativeMcpEntryRetirementFailed", {
|
|
30
|
+
readonly category: Schema.Literals<readonly ["conflict", "internal", "validation"]>;
|
|
31
|
+
readonly detail: Schema.String;
|
|
32
|
+
readonly filePath: Schema.String;
|
|
33
|
+
readonly cause: Schema.optional<Schema.Unknown>;
|
|
34
|
+
}>, import("effect/Cause").YieldableError>;
|
|
35
|
+
/**
|
|
36
|
+
* A native declaration could not be retired. `category` and `detail` are the
|
|
37
|
+
* producer's own decision so the surrounding closure reports the fact rather
|
|
38
|
+
* than a generic sentence.
|
|
39
|
+
*/
|
|
40
|
+
export declare class NativeMcpEntryRetirementFailed extends NativeMcpEntryRetirementFailed_base {
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Remove one native entry that a managed package replaced.
|
|
44
|
+
*
|
|
45
|
+
* A declaration that is already gone is a settled outcome: the conversion is
|
|
46
|
+
* idempotent, so re-running it after a partial retirement completes rather
|
|
47
|
+
* than refusing.
|
|
48
|
+
*/
|
|
49
|
+
export declare const retireNativeMcpEntry: (entry: NativeMcpEntryRef) => Effect.Effect<void, NativeMcpEntryRetirementFailed, FileSystem.FileSystem>;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=native-entry.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retiring a native MCP entry that a managed package now represents.
|
|
3
|
+
*
|
|
4
|
+
* Converting a native connection into an authored package leaves the original
|
|
5
|
+
* declaration in the agent's own config file. Removing it is the last step of
|
|
6
|
+
* that conversion and belongs inside the same transaction that publishes the
|
|
7
|
+
* package, so it lives in this capability beside `installMcpServer` rather
|
|
8
|
+
* than in the feature that discovered the native entry: the authoring routes
|
|
9
|
+
* that perform the conversion may not import a peer feature.
|
|
10
|
+
*
|
|
11
|
+
* The removal is conditional on the config still saying what it said when the
|
|
12
|
+
* conversion was planned. A native file that changed underneath is reported,
|
|
13
|
+
* never overwritten.
|
|
14
|
+
*
|
|
15
|
+
* @experimental This API is unstable and may change without notice.
|
|
16
|
+
*/
|
|
17
|
+
import * as Effect from "effect/Effect";
|
|
18
|
+
import * as FileSystem from "effect/FileSystem";
|
|
19
|
+
import * as Schema from "effect/Schema";
|
|
20
|
+
/**
|
|
21
|
+
* A native declaration could not be retired. `category` and `detail` are the
|
|
22
|
+
* producer's own decision so the surrounding closure reports the fact rather
|
|
23
|
+
* than a generic sentence.
|
|
24
|
+
*/
|
|
25
|
+
export class NativeMcpEntryRetirementFailed extends Schema.TaggedError()("NativeMcpEntryRetirementFailed", {
|
|
26
|
+
category: Schema.Literals(["conflict", "internal", "validation"]),
|
|
27
|
+
detail: Schema.String,
|
|
28
|
+
filePath: Schema.String,
|
|
29
|
+
cause: Schema.optional(Schema.Unknown),
|
|
30
|
+
}) {
|
|
31
|
+
}
|
|
32
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
33
|
+
/**
|
|
34
|
+
* Remove one native entry that a managed package replaced.
|
|
35
|
+
*
|
|
36
|
+
* A declaration that is already gone is a settled outcome: the conversion is
|
|
37
|
+
* idempotent, so re-running it after a partial retirement completes rather
|
|
38
|
+
* than refusing.
|
|
39
|
+
*/
|
|
40
|
+
export const retireNativeMcpEntry = (entry) => Effect.gen(function* () {
|
|
41
|
+
const fs = yield* FileSystem.FileSystem;
|
|
42
|
+
const exists = yield* fs.exists(entry.filePath).pipe(Effect.catch(() => Effect.succeed(false)));
|
|
43
|
+
if (!exists) {
|
|
44
|
+
return yield* new NativeMcpEntryRetirementFailed({
|
|
45
|
+
category: "conflict",
|
|
46
|
+
detail: `MCP config disappeared before package conversion: ${entry.filePath}`,
|
|
47
|
+
filePath: entry.filePath,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const raw = yield* fs.readFileString(entry.filePath).pipe(Effect.mapError((cause) => new NativeMcpEntryRetirementFailed({
|
|
51
|
+
category: "internal",
|
|
52
|
+
detail: `Failed to read MCP config: ${entry.filePath}`,
|
|
53
|
+
filePath: entry.filePath,
|
|
54
|
+
cause,
|
|
55
|
+
})));
|
|
56
|
+
const parsed = yield* Effect.try({
|
|
57
|
+
try: () => JSON.parse(raw),
|
|
58
|
+
catch: (cause) => new NativeMcpEntryRetirementFailed({
|
|
59
|
+
category: "validation",
|
|
60
|
+
detail: `Invalid JSON in MCP config: ${entry.filePath}`,
|
|
61
|
+
filePath: entry.filePath,
|
|
62
|
+
cause,
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
if (!isRecord(parsed)) {
|
|
66
|
+
return yield* new NativeMcpEntryRetirementFailed({
|
|
67
|
+
category: "conflict",
|
|
68
|
+
detail: `MCP config disappeared before package conversion: ${entry.filePath}`,
|
|
69
|
+
filePath: entry.filePath,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const servers = parsed[entry.serversKey];
|
|
73
|
+
if (!isRecord(servers)) {
|
|
74
|
+
return yield* new NativeMcpEntryRetirementFailed({
|
|
75
|
+
category: "conflict",
|
|
76
|
+
detail: `MCP server collection changed before package conversion: ${entry.filePath}`,
|
|
77
|
+
filePath: entry.filePath,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const declaration = servers[entry.name];
|
|
81
|
+
if (declaration === undefined)
|
|
82
|
+
return;
|
|
83
|
+
if (!isRecord(declaration)) {
|
|
84
|
+
return yield* new NativeMcpEntryRetirementFailed({
|
|
85
|
+
category: "conflict",
|
|
86
|
+
detail: `MCP server ${entry.name} changed before package conversion`,
|
|
87
|
+
filePath: entry.filePath,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const remaining = Object.fromEntries(Object.entries(servers).filter(([name]) => name !== entry.name));
|
|
91
|
+
yield* fs
|
|
92
|
+
.writeFileString(entry.filePath, `${JSON.stringify({ ...parsed, [entry.serversKey]: remaining }, null, 2)}\n`)
|
|
93
|
+
.pipe(Effect.mapError((cause) => new NativeMcpEntryRetirementFailed({
|
|
94
|
+
category: "internal",
|
|
95
|
+
detail: `Failed to replace native MCP config: ${entry.filePath}`,
|
|
96
|
+
filePath: entry.filePath,
|
|
97
|
+
cause,
|
|
98
|
+
})));
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=native-entry.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The system-keychain implementation of {@link McpSecretStore}.
|
|
3
|
+
*
|
|
4
|
+
* The native binding is loaded lazily: a machine without a usable keychain
|
|
5
|
+
* still installs MCP servers, reporting the credential action instead of
|
|
6
|
+
* failing the closure.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This API is unstable and may change without notice.
|
|
9
|
+
*/
|
|
10
|
+
import * as Layer from "effect/Layer";
|
|
11
|
+
import { McpSecretStore } from "./secret-store.js";
|
|
12
|
+
/** The system keychain, behind the MCP secret-store port. */
|
|
13
|
+
export declare const McpSecretStoreLive: Layer.Layer<McpSecretStore>;
|
|
14
|
+
//# sourceMappingURL=secret-store-live.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The system-keychain implementation of {@link McpSecretStore}.
|
|
3
|
+
*
|
|
4
|
+
* The native binding is loaded lazily: a machine without a usable keychain
|
|
5
|
+
* still installs MCP servers, reporting the credential action instead of
|
|
6
|
+
* failing the closure.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This API is unstable and may change without notice.
|
|
9
|
+
*/
|
|
10
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
11
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
12
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
13
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return path;
|
|
17
|
+
};
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as Layer from "effect/Layer";
|
|
20
|
+
import * as Option from "effect/Option";
|
|
21
|
+
import { MCP_SECRET_SERVICE, McpSecretStore, } from "./secret-store.js";
|
|
22
|
+
const keyringModuleSpecifier = ["@napi-rs", "keyring"].join("/");
|
|
23
|
+
const loadKeyringEntry = Effect.tryPromise({
|
|
24
|
+
try: async () => {
|
|
25
|
+
const keyring = await import(__rewriteRelativeImportExtension(keyringModuleSpecifier));
|
|
26
|
+
return keyring.Entry;
|
|
27
|
+
},
|
|
28
|
+
catch: () => undefined,
|
|
29
|
+
});
|
|
30
|
+
const service = {
|
|
31
|
+
read: (account) => Effect.gen(function* () {
|
|
32
|
+
const Entry = yield* loadKeyringEntry;
|
|
33
|
+
return yield* Effect.try({
|
|
34
|
+
try: () => Option.fromNullOr(new Entry(MCP_SECRET_SERVICE, account).getPassword()),
|
|
35
|
+
catch: () => undefined,
|
|
36
|
+
}).pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
37
|
+
}).pipe(Effect.catch(() => Effect.succeed(Option.none()))),
|
|
38
|
+
write: (account, value) => Effect.gen(function* () {
|
|
39
|
+
const Entry = yield* loadKeyringEntry;
|
|
40
|
+
return yield* Effect.try({
|
|
41
|
+
try: () => {
|
|
42
|
+
new Entry(MCP_SECRET_SERVICE, account).setPassword(value);
|
|
43
|
+
return "saved";
|
|
44
|
+
},
|
|
45
|
+
catch: () => undefined,
|
|
46
|
+
});
|
|
47
|
+
}).pipe(Effect.catch(() => Effect.succeed("failed"))),
|
|
48
|
+
erase: (account) => Effect.gen(function* () {
|
|
49
|
+
const Entry = yield* loadKeyringEntry;
|
|
50
|
+
return yield* Effect.try({
|
|
51
|
+
try: () => new Entry(MCP_SECRET_SERVICE, account).deletePassword() ? "deleted" : "absent",
|
|
52
|
+
catch: () => undefined,
|
|
53
|
+
});
|
|
54
|
+
}).pipe(Effect.catch(() => Effect.succeed("failed"))),
|
|
55
|
+
};
|
|
56
|
+
/** The system keychain, behind the MCP secret-store port. */
|
|
57
|
+
export const McpSecretStoreLive = Layer.succeed(McpSecretStore, service);
|
|
58
|
+
//# sourceMappingURL=secret-store-live.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credential store MCP connection secrets are persisted in, declared as a
|
|
3
|
+
* port so the materialization capability never reaches for a platform module
|
|
4
|
+
* directly.
|
|
5
|
+
*
|
|
6
|
+
* Secrets are addressed by an opaque account derived from the workspace scope
|
|
7
|
+
* root, the local connection name, the source identity, and the input name, so
|
|
8
|
+
* two connections that share a source keep separate credentials and a
|
|
9
|
+
* workspace never reads another workspace's.
|
|
10
|
+
*
|
|
11
|
+
* Every surface answers with a typed outcome rather than failing: a keychain
|
|
12
|
+
* that is unavailable, locked, or refuses a write is an ordinary condition the
|
|
13
|
+
* install reports as a warning, not a defect that aborts an applied closure.
|
|
14
|
+
*
|
|
15
|
+
* @experimental This API is unstable and may change without notice.
|
|
16
|
+
*/
|
|
17
|
+
import * as ServiceMap from "effect/Context";
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as Option from "effect/Option";
|
|
20
|
+
/** The credential-store service name every AXM MCP secret is filed under. */
|
|
21
|
+
export declare const MCP_SECRET_SERVICE = "axm-mcp";
|
|
22
|
+
/** What identifies one stored secret. */
|
|
23
|
+
export interface McpSecretIdentity {
|
|
24
|
+
/** Absolute, resolved root of the workspace scope holding the connection. */
|
|
25
|
+
readonly scopeRoot: string;
|
|
26
|
+
/** The agent-native MCP key the connection is installed as. */
|
|
27
|
+
readonly localName: string;
|
|
28
|
+
/** The resolution key (registry) or workspace identity of the source. */
|
|
29
|
+
readonly sourceIdentity: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The account one secret is stored under: an opaque digest of the four facts
|
|
33
|
+
* that make the credential unique, so no workspace path, connection name, or
|
|
34
|
+
* source appears in the credential store in clear text.
|
|
35
|
+
*/
|
|
36
|
+
export declare const mcpSecretAccount: (args: McpSecretIdentity & {
|
|
37
|
+
readonly inputName: string;
|
|
38
|
+
}) => string;
|
|
39
|
+
/** What persisting one secret settled as. */
|
|
40
|
+
export type McpSecretWriteOutcome = "saved" | "failed";
|
|
41
|
+
/** What erasing one secret settled as. */
|
|
42
|
+
export type McpSecretEraseOutcome = "deleted" | "absent" | "failed";
|
|
43
|
+
export interface McpSecretStoreService {
|
|
44
|
+
/** The stored value, or none when nothing is stored or the store is unavailable. */
|
|
45
|
+
readonly read: (account: string) => Effect.Effect<Option.Option<string>>;
|
|
46
|
+
/** Persist one value, answering whether the store accepted it. */
|
|
47
|
+
readonly write: (account: string, value: string) => Effect.Effect<McpSecretWriteOutcome>;
|
|
48
|
+
/** Erase one value, answering whether anything was there to erase. */
|
|
49
|
+
readonly erase: (account: string) => Effect.Effect<McpSecretEraseOutcome>;
|
|
50
|
+
}
|
|
51
|
+
declare const McpSecretStore_base: ServiceMap.ServiceClass<McpSecretStore, "@agentxm/extension-materialization/mcps/McpSecretStore", McpSecretStoreService>;
|
|
52
|
+
export declare class McpSecretStore extends McpSecretStore_base {
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=secret-store.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credential store MCP connection secrets are persisted in, declared as a
|
|
3
|
+
* port so the materialization capability never reaches for a platform module
|
|
4
|
+
* directly.
|
|
5
|
+
*
|
|
6
|
+
* Secrets are addressed by an opaque account derived from the workspace scope
|
|
7
|
+
* root, the local connection name, the source identity, and the input name, so
|
|
8
|
+
* two connections that share a source keep separate credentials and a
|
|
9
|
+
* workspace never reads another workspace's.
|
|
10
|
+
*
|
|
11
|
+
* Every surface answers with a typed outcome rather than failing: a keychain
|
|
12
|
+
* that is unavailable, locked, or refuses a write is an ordinary condition the
|
|
13
|
+
* install reports as a warning, not a defect that aborts an applied closure.
|
|
14
|
+
*
|
|
15
|
+
* @experimental This API is unstable and may change without notice.
|
|
16
|
+
*/
|
|
17
|
+
import * as ServiceMap from "effect/Context";
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as Option from "effect/Option";
|
|
20
|
+
import { createHash } from "node:crypto";
|
|
21
|
+
/** The credential-store service name every AXM MCP secret is filed under. */
|
|
22
|
+
export const MCP_SECRET_SERVICE = "axm-mcp";
|
|
23
|
+
/**
|
|
24
|
+
* The account one secret is stored under: an opaque digest of the four facts
|
|
25
|
+
* that make the credential unique, so no workspace path, connection name, or
|
|
26
|
+
* source appears in the credential store in clear text.
|
|
27
|
+
*/
|
|
28
|
+
export const mcpSecretAccount = (args) => createHash("sha256")
|
|
29
|
+
.update([args.scopeRoot, args.localName, args.sourceIdentity, args.inputName].join("\0"))
|
|
30
|
+
.digest("hex");
|
|
31
|
+
export class McpSecretStore extends ServiceMap.Service()("@agentxm/extension-materialization/mcps/McpSecretStore") {
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=secret-store.js.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed failure family for the pack manager and dependency resolution.
|
|
3
|
+
* Fields are domain facts; the application error boundary owns rendering,
|
|
4
|
+
* codes, and suggestions.
|
|
5
|
+
*
|
|
6
|
+
* @experimental This API is unstable and may change without notice.
|
|
7
|
+
*/
|
|
8
|
+
import type { PackDependencyResolutionFailure } from "@agentxm/extension-resolution";
|
|
9
|
+
declare const PackDefinitionInvalid_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
10
|
+
readonly _tag: "PackDefinitionInvalid";
|
|
11
|
+
} & Readonly<A>;
|
|
12
|
+
/**
|
|
13
|
+
* A pack source or manifest input did not validate. `detail` carries the
|
|
14
|
+
* site's fact sentence verbatim.
|
|
15
|
+
*/
|
|
16
|
+
export declare class PackDefinitionInvalid extends PackDefinitionInvalid_base<{
|
|
17
|
+
readonly detail: string;
|
|
18
|
+
readonly cause?: unknown;
|
|
19
|
+
}> {
|
|
20
|
+
}
|
|
21
|
+
declare const PackInstallStateMissing_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
22
|
+
readonly _tag: "PackInstallStateMissing";
|
|
23
|
+
} & Readonly<A>;
|
|
24
|
+
/** A lock entry was requested before install recorded the package state. */
|
|
25
|
+
export declare class PackInstallStateMissing extends PackInstallStateMissing_base<{
|
|
26
|
+
readonly name: string;
|
|
27
|
+
}> {
|
|
28
|
+
}
|
|
29
|
+
declare const PackArchiveFetchFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
30
|
+
readonly _tag: "PackArchiveFetchFailed";
|
|
31
|
+
} & Readonly<A>;
|
|
32
|
+
/** Fetching the pack archive from its source failed. */
|
|
33
|
+
export declare class PackArchiveFetchFailed extends PackArchiveFetchFailed_base<{
|
|
34
|
+
readonly message: string;
|
|
35
|
+
readonly cause: unknown;
|
|
36
|
+
}> {
|
|
37
|
+
}
|
|
38
|
+
declare const PackStagingFailed_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
39
|
+
readonly _tag: "PackStagingFailed";
|
|
40
|
+
} & Readonly<A>;
|
|
41
|
+
/** Staging fetched pack content into the canonical tree failed. */
|
|
42
|
+
export declare class PackStagingFailed extends PackStagingFailed_base<{
|
|
43
|
+
readonly packDir: string;
|
|
44
|
+
readonly cause: unknown;
|
|
45
|
+
}> {
|
|
46
|
+
}
|
|
47
|
+
/** Every failure the pack module constructs. */
|
|
48
|
+
export type PackManagerError = PackDefinitionInvalid | PackInstallStateMissing | PackArchiveFetchFailed | PackStagingFailed | PackDependencyResolutionFailure;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed failure family for the pack manager and dependency resolution.
|
|
3
|
+
* Fields are domain facts; the application error boundary owns rendering,
|
|
4
|
+
* codes, and suggestions.
|
|
5
|
+
*
|
|
6
|
+
* @experimental This API is unstable and may change without notice.
|
|
7
|
+
*/
|
|
8
|
+
import * as Data from "effect/Data";
|
|
9
|
+
/**
|
|
10
|
+
* A pack source or manifest input did not validate. `detail` carries the
|
|
11
|
+
* site's fact sentence verbatim.
|
|
12
|
+
*/
|
|
13
|
+
export class PackDefinitionInvalid extends Data.TaggedError("PackDefinitionInvalid") {
|
|
14
|
+
}
|
|
15
|
+
/** A lock entry was requested before install recorded the package state. */
|
|
16
|
+
export class PackInstallStateMissing extends Data.TaggedError("PackInstallStateMissing") {
|
|
17
|
+
}
|
|
18
|
+
/** Fetching the pack archive from its source failed. */
|
|
19
|
+
export class PackArchiveFetchFailed extends Data.TaggedError("PackArchiveFetchFailed") {
|
|
20
|
+
}
|
|
21
|
+
/** Staging fetched pack content into the canonical tree failed. */
|
|
22
|
+
export class PackStagingFailed extends Data.TaggedError("PackStagingFailed") {
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pack manager service.
|
|
3
|
+
*
|
|
4
|
+
* Implements ExtensionManager<PackRef>. Delegates to existing
|
|
5
|
+
* pack materialization functions and workspace service methods.
|
|
6
|
+
*
|
|
7
|
+
* @experimental This API is unstable and may change without notice.
|
|
8
|
+
*/
|
|
9
|
+
import * as FileSystem from "effect/FileSystem";
|
|
10
|
+
import * as Path from "effect/Path";
|
|
11
|
+
import * as Layer from "effect/Layer";
|
|
12
|
+
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
13
|
+
import { PackManager } from "../managers.js";
|
|
14
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
15
|
+
export declare const PackManagerLive: Layer.Layer<PackManager, never, FileSystem.FileSystem | Path.Path | WorkspaceMutations | SourceHostProviders>;
|
|
16
|
+
//# sourceMappingURL=manager.d.ts.map
|