@agentxm/extension-lifecycle 0.28.4-bootstrap.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +110 -0
- package/dist/src/configured-entry-resolution.d.ts +110 -0
- package/dist/src/configured-entry-resolution.js +723 -0
- package/dist/src/errors.d.ts +39 -0
- package/dist/src/errors.js +45 -0
- package/dist/src/failure-adapter.d.ts +35 -0
- package/dist/src/failure-adapter.js +23 -0
- package/dist/src/hooks/configured-agent-outcomes-provider.d.ts +18 -0
- package/dist/src/hooks/configured-agent-outcomes-provider.js +39 -0
- package/dist/src/hooks/manager.d.ts +15 -0
- package/dist/src/hooks/manager.js +751 -0
- package/dist/src/index.d.ts +38 -0
- package/dist/src/index.js +41 -0
- package/dist/src/internal/fs-helpers.d.ts +12 -0
- package/dist/src/internal/fs-helpers.js +13 -0
- package/dist/src/internal/integrity.d.ts +13 -0
- package/dist/src/internal/integrity.js +17 -0
- package/dist/src/knowledge/manager.d.ts +11 -0
- package/dist/src/knowledge/manager.js +655 -0
- package/dist/src/live.d.ts +18 -0
- package/dist/src/live.js +18 -0
- package/dist/src/mcps/manager.d.ts +16 -0
- package/dist/src/mcps/manager.js +213 -0
- package/dist/src/mcps/operations/artifact.d.ts +24 -0
- package/dist/src/mcps/operations/artifact.js +74 -0
- package/dist/src/mcps/operations/disable.d.ts +18 -0
- package/dist/src/mcps/operations/disable.js +113 -0
- package/dist/src/mcps/operations/enable.d.ts +18 -0
- package/dist/src/mcps/operations/enable.js +218 -0
- package/dist/src/mcps/operations/install.d.ts +59 -0
- package/dist/src/mcps/operations/install.js +566 -0
- package/dist/src/mcps/operations/sync-outcome.d.ts +10 -0
- package/dist/src/mcps/operations/sync-outcome.js +27 -0
- package/dist/src/mcps/operations/uninstall.d.ts +41 -0
- package/dist/src/mcps/operations/uninstall.js +189 -0
- package/dist/src/packs/dependency-resolution.d.ts +65 -0
- package/dist/src/packs/dependency-resolution.js +414 -0
- package/dist/src/packs/expansion.d.ts +59 -0
- package/dist/src/packs/expansion.js +44 -0
- package/dist/src/packs/manager.d.ts +16 -0
- package/dist/src/packs/manager.js +181 -0
- package/dist/src/packs/operations/install.d.ts +67 -0
- package/dist/src/packs/operations/install.js +156 -0
- package/dist/src/packs/resolved-dependency.d.ts +29 -0
- package/dist/src/packs/resolved-dependency.js +28 -0
- package/dist/src/registry-materialization.d.ts +52 -0
- package/dist/src/registry-materialization.js +67 -0
- package/dist/src/resolution-progress.d.ts +18 -0
- package/dist/src/resolution-progress.js +11 -0
- package/dist/src/resolution-timeout.d.ts +5 -0
- package/dist/src/resolution-timeout.js +11 -0
- package/dist/src/rules/manager.d.ts +20 -0
- package/dist/src/rules/manager.js +475 -0
- package/dist/src/skills/manager.d.ts +18 -0
- package/dist/src/skills/manager.js +346 -0
- package/dist/src/skills/materialization.d.ts +54 -0
- package/dist/src/skills/materialization.js +158 -0
- package/dist/src/skills/operations/disable.d.ts +31 -0
- package/dist/src/skills/operations/disable.js +110 -0
- package/dist/src/skills/operations/enable.d.ts +31 -0
- package/dist/src/skills/operations/enable.js +113 -0
- package/dist/src/skills/operations/install-result.d.ts +33 -0
- package/dist/src/skills/operations/install-result.js +10 -0
- package/dist/src/skills/operations/install.d.ts +67 -0
- package/dist/src/skills/operations/install.js +590 -0
- package/dist/src/skills/operations/source-hash.d.ts +2 -0
- package/dist/src/skills/operations/source-hash.js +6 -0
- package/dist/src/skills/operations/uninstall.d.ts +40 -0
- package/dist/src/skills/operations/uninstall.js +157 -0
- package/dist/src/skills/utils.d.ts +11 -0
- package/dist/src/skills/utils.js +29 -0
- package/dist/src/subagents/manager.d.ts +18 -0
- package/dist/src/subagents/manager.js +677 -0
- package/dist/src/subagents/operations/artifact.d.ts +18 -0
- package/dist/src/subagents/operations/artifact.js +43 -0
- package/dist/src/subagents/operations/disable.d.ts +32 -0
- package/dist/src/subagents/operations/disable.js +116 -0
- package/dist/src/subagents/operations/enable.d.ts +30 -0
- package/dist/src/subagents/operations/enable.js +160 -0
- package/dist/src/workflows/install-command/workflow.d.ts +57 -0
- package/dist/src/workflows/install-command/workflow.js +41 -0
- package/dist/src/workflows/uninstall-command/workflow.d.ts +42 -0
- package/dist/src/workflows/uninstall-command/workflow.js +29 -0
- package/package.json +62 -0
package/dist/src/live.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment-backed layers of the extension-lifecycle feature: the seven
|
|
3
|
+
* per-type manager implementations behind the extension-workspace manager
|
|
4
|
+
* contracts, and the hook-backed configured-agent-outcomes provider. Only
|
|
5
|
+
* application composition roots import this module.
|
|
6
|
+
*
|
|
7
|
+
* @experimental All exports from this module are unstable and may change without notice.
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
export { HookManagerLive } from "./hooks/manager.js";
|
|
11
|
+
export { HookConfiguredAgentOutcomesProviderLive } from "./hooks/configured-agent-outcomes-provider.js";
|
|
12
|
+
export { RuleManagerLive } from "./rules/manager.js";
|
|
13
|
+
export { SkillManagerLive } from "./skills/manager.js";
|
|
14
|
+
export { SubagentManagerLive } from "./subagents/manager.js";
|
|
15
|
+
export { McpServerManagerLive } from "./mcps/manager.js";
|
|
16
|
+
export { PackManagerLive } from "./packs/manager.js";
|
|
17
|
+
export { KnowledgeManagerLive } from "./knowledge/manager.js";
|
|
18
|
+
//# sourceMappingURL=live.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
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 HttpClient from "effect/unstable/http/HttpClient";
|
|
11
|
+
import * as Path from "effect/Path";
|
|
12
|
+
import * as Layer from "effect/Layer";
|
|
13
|
+
import { McpServerManager } from "@agentxm/extension-workspace";
|
|
14
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
15
|
+
export declare const McpServerManagerLive: Layer.Layer<McpServerManager, never, WorkspaceMutations | FileSystem.FileSystem | HttpClient.HttpClient | Path.Path>;
|
|
16
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1,213 @@
|
|
|
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 HttpClient from "effect/unstable/http/HttpClient";
|
|
11
|
+
import * as Path from "effect/Path";
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Layer from "effect/Layer";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import { McpConfigIoFailed, McpInstallStateMissing, McpRegistryOnlyInstall, removeMcpServerFromManifest, applyProjectionPlans, planSingletonProjection, } from "@agentxm/extension-workspace";
|
|
16
|
+
import { McpServerManager } from "@agentxm/extension-workspace";
|
|
17
|
+
import { configuredMcpServersToDiskRefs } from "@agentxm/extension-workspace";
|
|
18
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
19
|
+
import { canReuseInstalledPackage } from "@agentxm/extension-workspace";
|
|
20
|
+
import { materializeRegistryPackageWithTreeIntegrity } from "../registry-materialization.js";
|
|
21
|
+
import { computeExtensionPathsForLayout } from "@agentxm/workspace-state";
|
|
22
|
+
import { acceptedRegistryVersionForRef, validateExactResolvedVersion, } from "@agentxm/workspace-state";
|
|
23
|
+
import { decodeVersionSync } from "@agentxm/extension-model/unstable/version-constraints";
|
|
24
|
+
import { configuredRowsByName } from "@agentxm/workspace-state";
|
|
25
|
+
import { isObservedInstalled } from "@agentxm/workspace-state";
|
|
26
|
+
import { acceptedCanonicalObservation, prepareAcceptedCanonicalTransition, removableAcceptedCanonicalPath, } from "@agentxm/workspace-state";
|
|
27
|
+
import { protectWorkspacePath } from "@agentxm/workspace-state";
|
|
28
|
+
import { computeMaterializedTreeIntegrity } from "@agentxm/workspace-state";
|
|
29
|
+
// Build lock entry from registry ref
|
|
30
|
+
const buildMcpServerLockEntry = (ref, treeIntegrity) => ({
|
|
31
|
+
type: "registry",
|
|
32
|
+
sourceType: "registry",
|
|
33
|
+
packageFormat: "agentxm",
|
|
34
|
+
endpoint: ref.source.location,
|
|
35
|
+
extensionType: "mcp-server",
|
|
36
|
+
workspaceName: ref.server.name,
|
|
37
|
+
owner: ref.owner,
|
|
38
|
+
name: ref.name,
|
|
39
|
+
resolvedVersion: decodeVersionSync(ref.version),
|
|
40
|
+
integrity: Option.getOrElse(ref.integrity, () => ""),
|
|
41
|
+
sourceName: ref.source.name,
|
|
42
|
+
publisherBindingId: ref.publisherBindingId,
|
|
43
|
+
treeIntegrity,
|
|
44
|
+
});
|
|
45
|
+
// -----------------------------------------------------------------------------
|
|
46
|
+
// Live Layer
|
|
47
|
+
// -----------------------------------------------------------------------------
|
|
48
|
+
export const McpServerManagerLive = Layer.effect(McpServerManager, Effect.gen(function* () {
|
|
49
|
+
const ws = yield* WorkspaceMutations;
|
|
50
|
+
const fs = yield* FileSystem.FileSystem;
|
|
51
|
+
const httpClient = yield* HttpClient.HttpClient;
|
|
52
|
+
const path = yield* Path.Path;
|
|
53
|
+
const baseDir = ws.baseDir;
|
|
54
|
+
// Build a layer to provide FileSystem + Path to inner effects
|
|
55
|
+
const fsPathLayer = Layer.mergeAll(Layer.succeed(FileSystem.FileSystem, fs), Layer.succeed(Path.Path, path), Layer.succeed(HttpClient.HttpClient, httpClient));
|
|
56
|
+
const provide = (effect) => Effect.provide(effect, fsPathLayer);
|
|
57
|
+
const lastTreeIntegrities = new Map();
|
|
58
|
+
const materializeInstall = Effect.fn("McpServerManager.materializeInstall")(function* ({ ref, force }) {
|
|
59
|
+
if (ref.refType !== "registry") {
|
|
60
|
+
return yield* new McpRegistryOnlyInstall({
|
|
61
|
+
serverName: ref.server.name,
|
|
62
|
+
refType: ref.refType,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const registryRef = ref;
|
|
66
|
+
const canonicalPath = computeExtensionPathsForLayout(path.join, ws.layout, registryRef, "mcps", registryRef.name).canonicalPath;
|
|
67
|
+
const lockedEntry = yield* ws.getLockedMcpServer(registryRef.server.name);
|
|
68
|
+
const lockedVersion = acceptedRegistryVersionForRef(lockedEntry, registryRef);
|
|
69
|
+
const useExisting = yield* provide(canReuseInstalledPackage({
|
|
70
|
+
installedPath: canonicalPath,
|
|
71
|
+
force: force === true,
|
|
72
|
+
refVersion: registryRef.version,
|
|
73
|
+
hasIntegrity: Option.isSome(registryRef.integrity),
|
|
74
|
+
...(lockedVersion === undefined ? {} : { lockedVersion }),
|
|
75
|
+
existsFailureDetail: (target) => `Failed to check if canonical path exists: ${target}`,
|
|
76
|
+
}));
|
|
77
|
+
if (useExisting && Option.isSome(lockedEntry)) {
|
|
78
|
+
const observedTree = yield* provide(computeMaterializedTreeIntegrity(canonicalPath));
|
|
79
|
+
if (observedTree === lockedEntry.value.treeIntegrity) {
|
|
80
|
+
lastTreeIntegrities.set(registryRef.server.name, lockedEntry.value.treeIntegrity);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const materialized = yield* provide(materializeRegistryPackageWithTreeIntegrity({
|
|
85
|
+
baseDir,
|
|
86
|
+
destinationPath: canonicalPath,
|
|
87
|
+
sourceLocation: registryRef.source.location,
|
|
88
|
+
owner: registryRef.owner,
|
|
89
|
+
type: "mcp-server",
|
|
90
|
+
name: registryRef.name,
|
|
91
|
+
version: registryRef.version,
|
|
92
|
+
integrity: registryRef.integrity,
|
|
93
|
+
messages: {
|
|
94
|
+
integrityMismatchDetail: `Integrity mismatch for ${registryRef.name}@${registryRef.version}`,
|
|
95
|
+
},
|
|
96
|
+
}));
|
|
97
|
+
lastTreeIntegrities.set(registryRef.server.name, materialized.treeIntegrity);
|
|
98
|
+
}, Effect.asVoid);
|
|
99
|
+
const makeMaterializeRemoval = (retainCanonical) => Effect.fn("McpServerManager.materializeRemoval")(function* ({ target }) {
|
|
100
|
+
const configuredAgents = yield* ws.getConfiguredAgents();
|
|
101
|
+
yield* applyProjectionPlans(configuredAgents.map((agentId) => planSingletonProjection({
|
|
102
|
+
unitId: "mcp-server:native-config-entry",
|
|
103
|
+
// Multiple configured agents may share one native config file.
|
|
104
|
+
targetFile: `mcp:${target.name}:configured-agents`,
|
|
105
|
+
contributor: target,
|
|
106
|
+
adapter: {
|
|
107
|
+
observe: () => Effect.succeed({
|
|
108
|
+
unitId: "mcp-server:native-config-entry",
|
|
109
|
+
path: `${agentId}:${target.name}`,
|
|
110
|
+
present: true,
|
|
111
|
+
current: false,
|
|
112
|
+
expectedContributors: [],
|
|
113
|
+
observedContributors: [target.name],
|
|
114
|
+
}),
|
|
115
|
+
apply: () => provide(removeMcpServerFromManifest(agentId, {
|
|
116
|
+
workspaceRoot: baseDir,
|
|
117
|
+
scope: ws.scope,
|
|
118
|
+
serverName: target.name,
|
|
119
|
+
})).pipe(Effect.asVoid),
|
|
120
|
+
},
|
|
121
|
+
})));
|
|
122
|
+
if (retainCanonical)
|
|
123
|
+
return;
|
|
124
|
+
const canonical = yield* provide(acceptedCanonicalObservation({
|
|
125
|
+
workspace: ws,
|
|
126
|
+
type: "mcp-server",
|
|
127
|
+
name: target.name,
|
|
128
|
+
}));
|
|
129
|
+
const serverPath = removableAcceptedCanonicalPath(canonical);
|
|
130
|
+
if (Option.isSome(serverPath)) {
|
|
131
|
+
yield* protectWorkspacePath(serverPath.value);
|
|
132
|
+
yield* fs.remove(serverPath.value, { recursive: true, force: true }).pipe(Effect.mapError((cause) => new McpConfigIoFailed({
|
|
133
|
+
detail: `Failed to remove MCP server package: ${serverPath.value}`,
|
|
134
|
+
cause,
|
|
135
|
+
})));
|
|
136
|
+
}
|
|
137
|
+
}, Effect.asVoid);
|
|
138
|
+
const materializeUninstall = makeMaterializeRemoval(false);
|
|
139
|
+
const materializeDeactivate = makeMaterializeRemoval(true);
|
|
140
|
+
return {
|
|
141
|
+
type: "mcp-server",
|
|
142
|
+
runTransaction: ws.runTransaction,
|
|
143
|
+
isInstalled: Effect.fn("McpServerManager.isInstalled")(function* ({ target, }) {
|
|
144
|
+
return yield* isObservedInstalled(ws, "mcp-server", target.name);
|
|
145
|
+
}),
|
|
146
|
+
materializeInstall,
|
|
147
|
+
prepareSourceTransition: ({ ref }) => provide(prepareAcceptedCanonicalTransition({
|
|
148
|
+
workspace: ws,
|
|
149
|
+
type: "mcp-server",
|
|
150
|
+
name: ref.server.name,
|
|
151
|
+
ref,
|
|
152
|
+
})),
|
|
153
|
+
getConfiguredSource: Effect.fn("McpServerManager.getConfiguredSource")(function* ({ target, }) {
|
|
154
|
+
const configured = yield* ws.getConfiguredMcpServerEntries();
|
|
155
|
+
return Option.fromUndefinedOr(configured[target.name]?.source);
|
|
156
|
+
}),
|
|
157
|
+
isConfigured: Effect.fn("McpServerManager.isConfigured")(function* ({ target }) {
|
|
158
|
+
const configured = yield* ws.getConfiguredMcpServerEntries();
|
|
159
|
+
return configured[target.name] !== undefined;
|
|
160
|
+
}),
|
|
161
|
+
listMaterializable: Effect.fn("McpServerManager.listMaterializable")(function* () {
|
|
162
|
+
const configured = yield* ws.records
|
|
163
|
+
.rows("mcp-server")
|
|
164
|
+
.pipe(Effect.map(configuredRowsByName));
|
|
165
|
+
return yield* configuredMcpServersToDiskRefs({ fs, path, baseDir, scope: ws.scope, layout: ws.layout }, configured);
|
|
166
|
+
}),
|
|
167
|
+
materializeUninstall,
|
|
168
|
+
materializeDeactivate,
|
|
169
|
+
upsertSettingsEntry: ({ ref, versionRange, }) => {
|
|
170
|
+
if (ref.refType !== "registry")
|
|
171
|
+
return Effect.void.pipe(Effect.withSpan("McpServerManager.upsertSettingsEntry"));
|
|
172
|
+
const registryRef = ref;
|
|
173
|
+
return validateExactResolvedVersion(`mcpServers.${ref.server.name}.resolvedVersion`, registryRef.version).pipe(Effect.flatMap(() => {
|
|
174
|
+
const treeIntegrity = lastTreeIntegrities.get(registryRef.server.name);
|
|
175
|
+
if (treeIntegrity === undefined) {
|
|
176
|
+
return Effect.fail(new McpInstallStateMissing({ name: registryRef.server.name }));
|
|
177
|
+
}
|
|
178
|
+
const lockEntry = buildMcpServerLockEntry(registryRef, treeIntegrity);
|
|
179
|
+
return ws.setMcpServer({
|
|
180
|
+
name: ref.server.name,
|
|
181
|
+
lockEntry,
|
|
182
|
+
versionRange,
|
|
183
|
+
});
|
|
184
|
+
}), Effect.withSpan("McpServerManager.upsertSettingsEntry"));
|
|
185
|
+
},
|
|
186
|
+
removeSettingsEntry: ({ target }) => ws
|
|
187
|
+
.removeMcpServerSettings(target.name)
|
|
188
|
+
.pipe(Effect.withSpan("McpServerManager.removeSettingsEntry")),
|
|
189
|
+
upsertLockfileEntry: ({ ref }) => {
|
|
190
|
+
if (ref.refType !== "registry")
|
|
191
|
+
return ws
|
|
192
|
+
.removeMcpServerLock(ref.server.name)
|
|
193
|
+
.pipe(Effect.withSpan("McpServerManager.upsertLockfileEntry"));
|
|
194
|
+
const registryRef = ref;
|
|
195
|
+
return validateExactResolvedVersion(`mcpServers.${ref.server.name}.resolvedVersion`, registryRef.version).pipe(Effect.flatMap(() => {
|
|
196
|
+
const treeIntegrity = lastTreeIntegrities.get(registryRef.server.name);
|
|
197
|
+
if (treeIntegrity === undefined) {
|
|
198
|
+
return Effect.fail(new McpInstallStateMissing({ name: registryRef.server.name }));
|
|
199
|
+
}
|
|
200
|
+
const lockEntry = buildMcpServerLockEntry(registryRef, treeIntegrity);
|
|
201
|
+
return ws.setMcpServerLock({
|
|
202
|
+
name: ref.server.name,
|
|
203
|
+
lockEntry,
|
|
204
|
+
versionRange: Option.none(),
|
|
205
|
+
});
|
|
206
|
+
}), Effect.withSpan("McpServerManager.upsertLockfileEntry"));
|
|
207
|
+
},
|
|
208
|
+
removeLockfileEntry: ({ target }) => ws
|
|
209
|
+
.removeMcpServerLock(target.name)
|
|
210
|
+
.pipe(Effect.withSpan("McpServerManager.removeLockfileEntry")),
|
|
211
|
+
};
|
|
212
|
+
}));
|
|
213
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AgentId } from "@agentxm/extension-model/unstable/agents/types";
|
|
2
|
+
import type { McpServerLockEntry } from "@agentxm/workspace-state";
|
|
3
|
+
import type { JobStepArtifact, JobStepArtifactTarget } from "@agentxm/workspace-operations";
|
|
4
|
+
import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
|
|
5
|
+
export declare const mcpConfigSurface: (scope: WorkspaceScope) => string;
|
|
6
|
+
export declare const MCP_AGENT_CONFIG_SURFACE = ".mcp.json";
|
|
7
|
+
export declare const mcpServerVersion: (entry: McpServerLockEntry) => string | undefined;
|
|
8
|
+
export declare const mcpServerSourcePath: (scope: WorkspaceScope, entry: McpServerLockEntry) => string;
|
|
9
|
+
export declare const agentConfigTarget: (change: JobStepArtifactTarget["change"], agentIds: ReadonlyArray<AgentId>) => JobStepArtifactTarget | undefined;
|
|
10
|
+
export interface AgentMcpConfigOutcome {
|
|
11
|
+
readonly agentId: string;
|
|
12
|
+
readonly targets?: ReadonlyArray<JobStepArtifactTarget>;
|
|
13
|
+
}
|
|
14
|
+
export declare const agentConfigTargets: (outcomes: ReadonlyArray<AgentMcpConfigOutcome>) => ReadonlyArray<JobStepArtifactTarget>;
|
|
15
|
+
export declare const mcpSettingsTarget: (scope: WorkspaceScope, change: JobStepArtifactTarget["change"]) => JobStepArtifactTarget;
|
|
16
|
+
export declare const mcpSourceTarget: (scope: WorkspaceScope, entry: McpServerLockEntry, change: JobStepArtifactTarget["change"]) => JobStepArtifactTarget;
|
|
17
|
+
export declare const mcpServerArtifact: (args: {
|
|
18
|
+
readonly lockEntry: McpServerLockEntry | undefined;
|
|
19
|
+
readonly scope: JobStepArtifact["scope"];
|
|
20
|
+
readonly change: JobStepArtifact["change"];
|
|
21
|
+
readonly targets: ReadonlyArray<JobStepArtifactTarget>;
|
|
22
|
+
readonly agents?: ReadonlyArray<string>;
|
|
23
|
+
}) => JobStepArtifact;
|
|
24
|
+
//# sourceMappingURL=artifact.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ACQUIRED_EXTENSIONS_DIR } from "@agentxm/workspace-state";
|
|
2
|
+
import { acquiredExtensionDisplayPathFromLockEntry } from "@agentxm/workspace-state";
|
|
3
|
+
export const mcpConfigSurface = (scope) => scope === "project"
|
|
4
|
+
? "axm.json / axm-lock.yaml"
|
|
5
|
+
: ".axm/workspace/axm.json / .axm/workspace/axm-lock.yaml";
|
|
6
|
+
export const MCP_AGENT_CONFIG_SURFACE = ".mcp.json";
|
|
7
|
+
export const mcpServerVersion = (entry) => entry.type === "registry" ? entry.resolvedVersion : undefined;
|
|
8
|
+
export const mcpServerSourcePath = (scope, entry) => acquiredExtensionDisplayPathFromLockEntry(scope === "project" ? ACQUIRED_EXTENSIONS_DIR : ".axm/workspace/agent_extensions", entry, "mcps", entry.workspaceName);
|
|
9
|
+
export const agentConfigTarget = (change, agentIds) => agentIds.length === 0
|
|
10
|
+
? undefined
|
|
11
|
+
: {
|
|
12
|
+
path: MCP_AGENT_CONFIG_SURFACE,
|
|
13
|
+
change,
|
|
14
|
+
agentIds,
|
|
15
|
+
};
|
|
16
|
+
const mergeTargetChange = (current, next) => {
|
|
17
|
+
if (current === "created" || next === "created")
|
|
18
|
+
return "created";
|
|
19
|
+
if (current === "updated" || next === "updated")
|
|
20
|
+
return "updated";
|
|
21
|
+
if (current === "removed" || next === "removed")
|
|
22
|
+
return "removed";
|
|
23
|
+
return "unchanged";
|
|
24
|
+
};
|
|
25
|
+
export const agentConfigTargets = (outcomes) => {
|
|
26
|
+
const grouped = new Map();
|
|
27
|
+
for (const outcome of outcomes) {
|
|
28
|
+
for (const target of outcome.targets ?? []) {
|
|
29
|
+
const existing = grouped.get(target.path);
|
|
30
|
+
if (existing === undefined) {
|
|
31
|
+
grouped.set(target.path, {
|
|
32
|
+
path: target.path,
|
|
33
|
+
change: target.change,
|
|
34
|
+
agentIds: [outcome.agentId],
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
existing.change = mergeTargetChange(existing.change, target.change);
|
|
39
|
+
existing.agentIds.push(outcome.agentId);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return Array.from(grouped.values()).map((target) => ({
|
|
43
|
+
path: target.path,
|
|
44
|
+
change: target.change,
|
|
45
|
+
agentIds: target.agentIds,
|
|
46
|
+
}));
|
|
47
|
+
};
|
|
48
|
+
export const mcpSettingsTarget = (scope, change) => ({
|
|
49
|
+
path: scope === "project" ? "axm.json" : ".axm/workspace/axm.json",
|
|
50
|
+
change,
|
|
51
|
+
});
|
|
52
|
+
export const mcpSourceTarget = (scope, entry, change) => ({
|
|
53
|
+
path: mcpServerSourcePath(scope, entry),
|
|
54
|
+
change,
|
|
55
|
+
});
|
|
56
|
+
export const mcpServerArtifact = (args) => {
|
|
57
|
+
const version = args.lockEntry === undefined ? undefined : mcpServerVersion(args.lockEntry);
|
|
58
|
+
return {
|
|
59
|
+
path: args.lockEntry === undefined
|
|
60
|
+
? mcpConfigSurface(args.scope)
|
|
61
|
+
: mcpServerSourcePath(args.scope, args.lockEntry),
|
|
62
|
+
scope: args.scope,
|
|
63
|
+
change: args.change,
|
|
64
|
+
...(args.agents === undefined ? {} : { agents: args.agents }),
|
|
65
|
+
...(version === undefined ? {} : { version }),
|
|
66
|
+
...(args.targets.length === 0
|
|
67
|
+
? {}
|
|
68
|
+
: {
|
|
69
|
+
fileCount: args.targets.length,
|
|
70
|
+
targets: args.targets,
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disable MCP server executor.
|
|
3
|
+
*
|
|
4
|
+
* @experimental This API is unstable and may change without notice.
|
|
5
|
+
*/
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as FileSystem from "effect/FileSystem";
|
|
8
|
+
import * as Path from "effect/Path";
|
|
9
|
+
import { CodingAgentRepository } from "@agentxm/extension-workspace";
|
|
10
|
+
import type { StepFailure } from "@agentxm/workspace-operations";
|
|
11
|
+
import type { JobStepResult, Operation } from "@agentxm/workspace-operations";
|
|
12
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
13
|
+
import { LifecycleFailureAdapter } from "../../failure-adapter.js";
|
|
14
|
+
export type DisableMcpServerOperation = Operation<"disable-mcp-server", {
|
|
15
|
+
readonly serverName: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const disableMcpServer: (op: DisableMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | CodingAgentRepository | LifecycleFailureAdapter>;
|
|
18
|
+
//# sourceMappingURL=disable.d.ts.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disable MCP server executor.
|
|
3
|
+
*
|
|
4
|
+
* @experimental This API is unstable and may change without notice.
|
|
5
|
+
*/
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as FileSystem from "effect/FileSystem";
|
|
8
|
+
import * as Path from "effect/Path";
|
|
9
|
+
import { CodingAgentRepository, inspectAgentMcpServer, sharedMcpTargetPolicyConflict, } from "@agentxm/extension-workspace";
|
|
10
|
+
import { appendWarningsToMessage } from "@agentxm/workspace-operations";
|
|
11
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
12
|
+
import { agentConfigTargets, mcpServerArtifact, mcpSettingsTarget } from "./artifact.js";
|
|
13
|
+
import { mcpSyncWarnings, requireSuccessfulMcpSync } from "./sync-outcome.js";
|
|
14
|
+
import { isMcpServerApplicableToAgent } from "@agentxm/workspace-state";
|
|
15
|
+
import { LifecycleFailureAdapter, withAdaptedStepFailures } from "../../failure-adapter.js";
|
|
16
|
+
import { ExtensionLifecycleFailed } from "../../errors.js";
|
|
17
|
+
export const disableMcpServer = (op) => Effect.gen(function* () {
|
|
18
|
+
const fs = yield* FileSystem.FileSystem;
|
|
19
|
+
const path = yield* Path.Path;
|
|
20
|
+
const ws = yield* WorkspaceMutations;
|
|
21
|
+
const agentRepo = yield* CodingAgentRepository;
|
|
22
|
+
const configured = yield* ws.getConfiguredMcpServerEntries();
|
|
23
|
+
const entry = configured[op.args.serverName];
|
|
24
|
+
if (entry === undefined) {
|
|
25
|
+
return yield* new ExtensionLifecycleFailed({
|
|
26
|
+
category: "not_found",
|
|
27
|
+
detail: `MCP server "${op.args.serverName}" not found in settings`,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const agents = yield* agentRepo.getConfiguredAgents();
|
|
31
|
+
const sharedTargetConflict = sharedMcpTargetPolicyConflict({
|
|
32
|
+
entry,
|
|
33
|
+
agentIds: agents.map((agent) => agent.id),
|
|
34
|
+
scope: ws.scope,
|
|
35
|
+
});
|
|
36
|
+
if (sharedTargetConflict !== undefined) {
|
|
37
|
+
return yield* new ExtensionLifecycleFailed({
|
|
38
|
+
category: "conflict",
|
|
39
|
+
detail: sharedTargetConflict,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
const outcomes = yield* ws.runTransaction({
|
|
43
|
+
transition: Effect.gen(function* () {
|
|
44
|
+
const synced = yield* Effect.forEach(agents, (agent) => Effect.gen(function* () {
|
|
45
|
+
if (isMcpServerApplicableToAgent(entry, agent.id)) {
|
|
46
|
+
return yield* agent.removeMcpServer({
|
|
47
|
+
workspaceRoot: ws.baseDir,
|
|
48
|
+
scope: ws.scope,
|
|
49
|
+
serverName: op.args.serverName,
|
|
50
|
+
disableOnly: true,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const inspection = yield* inspectAgentMcpServer({
|
|
54
|
+
workspaceRoot: ws.baseDir,
|
|
55
|
+
scope: ws.scope,
|
|
56
|
+
agentId: agent.id,
|
|
57
|
+
serverName: op.args.serverName,
|
|
58
|
+
entry,
|
|
59
|
+
});
|
|
60
|
+
if (inspection.status === "unmanaged") {
|
|
61
|
+
return yield* new ExtensionLifecycleFailed({
|
|
62
|
+
category: "conflict",
|
|
63
|
+
detail: `${agent.id} has an unmanaged MCP server named ${op.args.serverName}; AXM will not remove it while applying the target policy`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return inspection.status === "drift"
|
|
67
|
+
? yield* agent.removeMcpServer({
|
|
68
|
+
workspaceRoot: ws.baseDir,
|
|
69
|
+
scope: ws.scope,
|
|
70
|
+
serverName: op.args.serverName,
|
|
71
|
+
})
|
|
72
|
+
: { _tag: "success", targets: [] };
|
|
73
|
+
}), { concurrency: "unbounded" });
|
|
74
|
+
yield* requireSuccessfulMcpSync(op.args.serverName, agents.map((agent, index) => ({
|
|
75
|
+
agentId: agent.id,
|
|
76
|
+
outcome: synced[index] ?? {
|
|
77
|
+
_tag: "failed",
|
|
78
|
+
reason: "Agent sync returned no outcome",
|
|
79
|
+
},
|
|
80
|
+
})));
|
|
81
|
+
yield* ws.updateMcpServerEntry(op.args.serverName, (current) => ({
|
|
82
|
+
...current,
|
|
83
|
+
enabled: false,
|
|
84
|
+
}));
|
|
85
|
+
return synced;
|
|
86
|
+
}).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path)),
|
|
87
|
+
validate: () => Effect.void,
|
|
88
|
+
});
|
|
89
|
+
const syncedAgents = agents.flatMap((agent, index) => {
|
|
90
|
+
const outcome = outcomes[index];
|
|
91
|
+
return outcome !== undefined && "targets" in outcome
|
|
92
|
+
? [{ agentId: agent.id, targets: outcome.targets }]
|
|
93
|
+
: [];
|
|
94
|
+
});
|
|
95
|
+
const warnings = mcpSyncWarnings(op.args.serverName, agents.map((agent, index) => ({
|
|
96
|
+
agentId: agent.id,
|
|
97
|
+
outcome: outcomes[index] ?? {
|
|
98
|
+
_tag: "failed",
|
|
99
|
+
reason: "Agent sync returned no outcome",
|
|
100
|
+
},
|
|
101
|
+
})));
|
|
102
|
+
return {
|
|
103
|
+
result: "success",
|
|
104
|
+
message: appendWarningsToMessage(`Disabled ${op.args.serverName}`, warnings),
|
|
105
|
+
artifact: mcpServerArtifact({
|
|
106
|
+
lockEntry: undefined,
|
|
107
|
+
scope: ws.scope,
|
|
108
|
+
change: "updated",
|
|
109
|
+
targets: [mcpSettingsTarget(ws.scope, "updated"), ...agentConfigTargets(syncedAgents)],
|
|
110
|
+
}),
|
|
111
|
+
};
|
|
112
|
+
}).pipe(withAdaptedStepFailures);
|
|
113
|
+
//# sourceMappingURL=disable.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enable MCP server executor.
|
|
3
|
+
*
|
|
4
|
+
* @experimental This API is unstable and may change without notice.
|
|
5
|
+
*/
|
|
6
|
+
import * as FileSystem from "effect/FileSystem";
|
|
7
|
+
import * as Path from "effect/Path";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import { CodingAgentRepository } from "@agentxm/extension-workspace";
|
|
10
|
+
import type { StepFailure } from "@agentxm/workspace-operations";
|
|
11
|
+
import type { JobStepResult, Operation } from "@agentxm/workspace-operations";
|
|
12
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
13
|
+
import { LifecycleFailureAdapter } from "../../failure-adapter.js";
|
|
14
|
+
export type EnableMcpServerOperation = Operation<"enable-mcp-server", {
|
|
15
|
+
readonly serverName: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const enableMcpServer: (op: EnableMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | CodingAgentRepository | LifecycleFailureAdapter>;
|
|
18
|
+
//# sourceMappingURL=enable.d.ts.map
|