@agentxm/extension-lifecycle 0.28.11 → 0.28.13
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/dist/src/activation/display-paths.d.ts +25 -0
- package/dist/src/activation/display-paths.js +25 -0
- package/dist/src/activation/errors.d.ts +16 -0
- package/dist/src/activation/errors.js +7 -0
- package/dist/src/activation/set-activation.d.ts +134 -0
- package/dist/src/activation/set-activation.js +772 -0
- package/dist/src/demote/demote-to-external-source.d.ts +82 -0
- package/dist/src/demote/demote-to-external-source.js +233 -0
- package/dist/src/errors.d.ts +0 -8
- package/dist/src/errors.js +0 -8
- package/dist/src/glob.d.ts +35 -0
- package/dist/src/glob.js +75 -0
- package/dist/src/hooks/configured-agent-outcomes-provider.d.ts +7 -3
- package/dist/src/hooks/configured-agent-outcomes-provider.js +11 -4
- package/dist/src/hooks/install/plan.d.ts +45 -0
- package/dist/src/hooks/install/plan.js +224 -0
- package/dist/src/hooks/uninstall/plan.d.ts +20 -0
- package/dist/src/hooks/uninstall/plan.js +77 -0
- package/dist/src/index.d.ts +48 -16
- package/dist/src/index.js +60 -17
- package/dist/src/install/aggregate-projection-step.d.ts +16 -0
- package/dist/src/install/aggregate-projection-step.js +49 -0
- package/dist/src/install/configured.d.ts +65 -0
- package/dist/src/install/configured.js +406 -0
- package/dist/src/install/inline-mcp-operation.d.ts +4 -0
- package/dist/src/install/inline-mcp-operation.js +25 -0
- package/dist/src/install/install-extensions.d.ts +110 -0
- package/dist/src/install/install-extensions.js +282 -0
- package/dist/src/install/per-type-install.d.ts +12 -0
- package/dist/src/install/per-type-install.js +12 -0
- package/dist/src/install/registry-install-target.d.ts +35 -0
- package/dist/src/install/registry-install-target.js +66 -0
- package/dist/src/install/registry-login-suggestion.d.ts +21 -0
- package/dist/src/install/registry-login-suggestion.js +34 -0
- package/dist/src/install/registry-source-resolution.d.ts +54 -0
- package/dist/src/install/registry-source-resolution.js +216 -0
- package/dist/src/install/root-intent.d.ts +19 -0
- package/dist/src/install/root-intent.js +122 -0
- package/dist/src/install/selection-interaction.d.ts +46 -0
- package/dist/src/install/selection-interaction.js +22 -0
- package/dist/src/install/vocabulary.d.ts +143 -0
- package/dist/src/install/vocabulary.js +29 -0
- package/dist/src/knowledge/install/plan.d.ts +35 -0
- package/dist/src/knowledge/install/plan.js +128 -0
- package/dist/src/knowledge/uninstall/plan.d.ts +23 -0
- package/dist/src/knowledge/uninstall/plan.js +140 -0
- package/dist/src/live.d.ts +4 -11
- package/dist/src/live.js +4 -11
- package/dist/src/mcps/install/plan.d.ts +65 -0
- package/dist/src/mcps/install/plan.js +301 -0
- package/dist/src/mcps/operations/disable.d.ts +5 -3
- package/dist/src/mcps/operations/disable.js +6 -4
- package/dist/src/mcps/operations/enable.d.ts +5 -3
- package/dist/src/mcps/operations/enable.js +8 -6
- package/dist/src/mcps/operations/sync-outcome.d.ts +1 -1
- package/dist/src/mcps/operations/uninstall.d.ts +5 -3
- package/dist/src/mcps/operations/uninstall.js +4 -4
- package/dist/src/mcps/uninstall/plan.d.ts +24 -0
- package/dist/src/mcps/uninstall/plan.js +109 -0
- package/dist/src/packs/artifact.d.ts +21 -0
- package/dist/src/packs/artifact.js +32 -0
- package/dist/src/packs/constraint-gate.d.ts +30 -0
- package/dist/src/packs/constraint-gate.js +76 -0
- package/dist/src/packs/expansion.d.ts +13 -14
- package/dist/src/packs/expansion.js +1 -2
- package/dist/src/packs/graph-transition.d.ts +64 -0
- package/dist/src/packs/graph-transition.js +219 -0
- package/dist/src/packs/install/plan.d.ts +95 -0
- package/dist/src/packs/install/plan.js +845 -0
- package/dist/src/packs/member-install-step.d.ts +29 -0
- package/dist/src/packs/member-install-step.js +156 -0
- package/dist/src/packs/operations/install.d.ts +3 -3
- package/dist/src/packs/operations/install.js +5 -5
- package/dist/src/packs/promote-authored-pack.d.ts +86 -0
- package/dist/src/packs/promote-authored-pack.js +239 -0
- package/dist/src/packs/resolved-dependency.d.ts +9 -26
- package/dist/src/packs/resolved-dependency.js +8 -20
- package/dist/src/packs/uninstall/plan.d.ts +66 -0
- package/dist/src/packs/uninstall/plan.js +344 -0
- package/dist/src/packs/uninstall/readiness.d.ts +50 -0
- package/dist/src/packs/uninstall/readiness.js +130 -0
- package/dist/src/publisher-binding.d.ts +8 -40
- package/dist/src/publisher-binding.js +8 -46
- package/dist/src/rules/install/plan.d.ts +35 -0
- package/dist/src/rules/install/plan.js +133 -0
- package/dist/src/rules/uninstall/plan.d.ts +19 -0
- package/dist/src/rules/uninstall/plan.js +54 -0
- package/dist/src/skills/install/bundled.d.ts +73 -0
- package/dist/src/skills/install/bundled.js +244 -0
- package/dist/src/skills/install/plan.d.ts +72 -0
- package/dist/src/skills/install/plan.js +429 -0
- package/dist/src/skills/install/selection.d.ts +26 -0
- package/dist/src/skills/install/selection.js +41 -0
- package/dist/src/skills/install/source.d.ts +21 -0
- package/dist/src/skills/install/source.js +76 -0
- package/dist/src/skills/operations/disable.d.ts +3 -2
- package/dist/src/skills/operations/disable.js +7 -11
- package/dist/src/skills/operations/enable.d.ts +3 -2
- package/dist/src/skills/operations/enable.js +6 -8
- package/dist/src/skills/operations/install.d.ts +4 -4
- package/dist/src/skills/operations/install.js +13 -12
- package/dist/src/skills/uninstall/plan.d.ts +23 -0
- package/dist/src/skills/uninstall/plan.js +165 -0
- package/dist/src/skills/utils.js +1 -1
- package/dist/src/step-failure-conversion.d.ts +44 -0
- package/dist/src/step-failure-conversion.js +26 -0
- package/dist/src/step-failure.d.ts +29 -0
- package/dist/src/step-failure.js +130 -0
- package/dist/src/subagents/install/plan.d.ts +49 -0
- package/dist/src/subagents/install/plan.js +270 -0
- package/dist/src/subagents/install/selection.d.ts +26 -0
- package/dist/src/subagents/install/selection.js +37 -0
- package/dist/src/subagents/install/source.d.ts +18 -0
- package/dist/src/subagents/install/source.js +72 -0
- package/dist/src/subagents/operations/disable.d.ts +5 -3
- package/dist/src/subagents/operations/disable.js +5 -3
- package/dist/src/subagents/operations/enable.d.ts +5 -3
- package/dist/src/subagents/operations/enable.js +17 -12
- package/dist/src/subagents/uninstall/plan.d.ts +20 -0
- package/dist/src/subagents/uninstall/plan.js +142 -0
- package/dist/src/test-packages.d.ts +34 -0
- package/dist/src/test-packages.js +111 -0
- package/dist/src/test-registry.d.ts +78 -0
- package/dist/src/test-registry.js +223 -0
- package/dist/src/testing.d.ts +108 -0
- package/dist/src/testing.js +241 -0
- package/dist/src/uninstall/retention-policy.d.ts +21 -0
- package/dist/src/uninstall/retention-policy.js +28 -0
- package/dist/src/uninstall/root-intent.d.ts +17 -0
- package/dist/src/uninstall/root-intent.js +101 -0
- package/dist/src/uninstall/uninstall-extensions.d.ts +61 -0
- package/dist/src/uninstall/uninstall-extensions.js +127 -0
- package/dist/src/uninstall/vocabulary.d.ts +40 -0
- package/dist/src/uninstall/vocabulary.js +14 -0
- package/dist/src/update/atomicity.d.ts +22 -0
- package/dist/src/update/atomicity.js +23 -0
- package/dist/src/update/blockers.d.ts +31 -0
- package/dist/src/update/blockers.js +78 -0
- package/dist/src/update/configured.d.ts +78 -0
- package/dist/src/update/configured.js +546 -0
- package/dist/src/update/root-request.d.ts +39 -0
- package/dist/src/update/root-request.js +117 -0
- package/dist/src/update/selective/plan.d.ts +45 -0
- package/dist/src/update/selective/plan.js +61 -0
- package/dist/src/update/selective/requirements.d.ts +17 -0
- package/dist/src/update/selective/requirements.js +14 -0
- package/dist/src/update/selective/selection.d.ts +63 -0
- package/dist/src/update/selective/selection.js +85 -0
- package/dist/src/update/selective/skills.d.ts +55 -0
- package/dist/src/update/selective/skills.js +596 -0
- package/dist/src/update/selective/subagents.d.ts +52 -0
- package/dist/src/update/selective/subagents.js +331 -0
- package/dist/src/update/selective/use-case.d.ts +121 -0
- package/dist/src/update/selective/use-case.js +28 -0
- package/dist/src/update/selective/vocabulary.d.ts +43 -0
- package/dist/src/update/selective/vocabulary.js +28 -0
- package/dist/src/update/selector.d.ts +72 -0
- package/dist/src/update/selector.js +120 -0
- package/dist/src/update/targeted-plan.d.ts +30 -0
- package/dist/src/update/targeted-plan.js +113 -0
- package/dist/src/update/update-extensions.d.ts +164 -0
- package/dist/src/update/update-extensions.js +579 -0
- package/dist/src/workspace-paths.d.ts +31 -0
- package/dist/src/workspace-paths.js +46 -0
- package/package.json +22 -12
- package/dist/src/configured-entry-resolution.d.ts +0 -111
- package/dist/src/configured-entry-resolution.js +0 -731
- package/dist/src/failure-adapter.d.ts +0 -35
- package/dist/src/failure-adapter.js +0 -23
- package/dist/src/hooks/manager.d.ts +0 -15
- package/dist/src/hooks/manager.js +0 -769
- package/dist/src/internal/fs-helpers.d.ts +0 -12
- package/dist/src/internal/fs-helpers.js +0 -13
- package/dist/src/internal/integrity.d.ts +0 -13
- package/dist/src/internal/integrity.js +0 -17
- package/dist/src/knowledge/manager.d.ts +0 -11
- package/dist/src/knowledge/manager.js +0 -711
- package/dist/src/mcps/manager.d.ts +0 -16
- package/dist/src/mcps/manager.js +0 -247
- package/dist/src/mcps/operations/artifact.d.ts +0 -24
- package/dist/src/mcps/operations/artifact.js +0 -74
- package/dist/src/mcps/operations/install.d.ts +0 -78
- package/dist/src/mcps/operations/install.js +0 -596
- package/dist/src/packs/dependency-resolution.d.ts +0 -65
- package/dist/src/packs/dependency-resolution.js +0 -414
- package/dist/src/packs/manager.d.ts +0 -16
- package/dist/src/packs/manager.js +0 -181
- package/dist/src/registry-materialization.d.ts +0 -52
- package/dist/src/registry-materialization.js +0 -72
- package/dist/src/release-age-posture.d.ts +0 -23
- package/dist/src/release-age-posture.js +0 -15
- package/dist/src/resolution-timeout.d.ts +0 -5
- package/dist/src/resolution-timeout.js +0 -11
- package/dist/src/rules/manager.d.ts +0 -20
- package/dist/src/rules/manager.js +0 -480
- package/dist/src/skills/manager.d.ts +0 -18
- package/dist/src/skills/manager.js +0 -346
- package/dist/src/skills/materialization.d.ts +0 -54
- package/dist/src/skills/materialization.js +0 -158
- package/dist/src/skills/operations/source-hash.d.ts +0 -2
- package/dist/src/skills/operations/source-hash.js +0 -6
- package/dist/src/subagents/manager.d.ts +0 -18
- package/dist/src/subagents/manager.js +0 -722
- package/dist/src/workflows/install-command/workflow.d.ts +0 -56
- package/dist/src/workflows/install-command/workflow.js +0 -46
- package/dist/src/workflows/uninstall-command/workflow.d.ts +0 -42
- package/dist/src/workflows/uninstall-command/workflow.js +0 -29
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installing an MCP connection from the registry.
|
|
3
|
+
*
|
|
4
|
+
* An MCP server is acquired once and referenced by a local connection name, so
|
|
5
|
+
* this decides who owns that name, which version constraint every origin
|
|
6
|
+
* referencing the same server agrees on, and whether the selected workspace
|
|
7
|
+
* scope can hold an MCP configuration at all.
|
|
8
|
+
*
|
|
9
|
+
* @experimental This API is unstable and may change without notice.
|
|
10
|
+
*/
|
|
11
|
+
import * as Effect from "effect/Effect";
|
|
12
|
+
import * as Option from "effect/Option";
|
|
13
|
+
import * as Result from "effect/Result";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import { installMcpServer } from "@agentxm/extension-materialization";
|
|
16
|
+
import { CONFIGURABLE_AGENTS_BY_ID, } from "@agentxm/extension-model/unstable/agent-capabilities";
|
|
17
|
+
import { ExtensionNameSchema, } from "@agentxm/extension-model/unstable/extensions";
|
|
18
|
+
import { intersectVersionConstraints } from "@agentxm/extension-model/unstable/version-constraints";
|
|
19
|
+
import { SourceHostProviders, resolveSource } from "@agentxm/extension-sources";
|
|
20
|
+
import { operationPresentation } from "@agentxm/workspace-operations";
|
|
21
|
+
import { WorkspaceMutations, mcpRegistryResolutionKey } from "@agentxm/workspace-state";
|
|
22
|
+
import { lifecycleStepFailure } from "../../step-failure.js";
|
|
23
|
+
import { registryLoginSuggestions } from "../../install/registry-login-suggestion.js";
|
|
24
|
+
import { parseRegistryInstallTarget } from "../../install/registry-install-target.js";
|
|
25
|
+
import { installRefused, } from "../../install/vocabulary.js";
|
|
26
|
+
const LOCAL_NAME_RULE = "Local MCP names must be max 64 chars, use lowercase letters, numbers, and hyphens, and cannot start or end with a hyphen.";
|
|
27
|
+
const REGISTRY_ONLY = "Use @owner/mcps/server-name or just server-name.";
|
|
28
|
+
/**
|
|
29
|
+
* Decode repeated `--env KEY=VALUE` inputs into a record. Later occurrences of
|
|
30
|
+
* the same key win. Registry installs resolve declared inputs by name, so a
|
|
31
|
+
* bare `KEY` (passthrough from the ambient environment, as `axm mcps add`
|
|
32
|
+
* allows) is refused here rather than silently resolving to nothing.
|
|
33
|
+
*/
|
|
34
|
+
export const parseMcpEnvInputs = (env) => Effect.gen(function* () {
|
|
35
|
+
const parsed = {};
|
|
36
|
+
for (const value of env) {
|
|
37
|
+
const separator = value.indexOf("=");
|
|
38
|
+
if (separator <= 0) {
|
|
39
|
+
return yield* installRefused({
|
|
40
|
+
category: "usage",
|
|
41
|
+
detail: "--env must use KEY=VALUE format",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
parsed[value.slice(0, separator)] = value.slice(separator + 1);
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
});
|
|
48
|
+
const isConfigurableAgentId = (agentId) => agentId in CONFIGURABLE_AGENTS_BY_ID;
|
|
49
|
+
const decodeLocalName = (value) => Schema.decodeUnknownEffect(ExtensionNameSchema)(value).pipe(Effect.mapError((cause) => installRefused({ category: "validation", detail: LOCAL_NAME_RULE, cause })));
|
|
50
|
+
/** Read the MCP source grammar and settle the local connection name. */
|
|
51
|
+
export const parseMcpServerInstallRequest = Effect.fn("InstallExtensions.parseMcpRequest")(function* (args) {
|
|
52
|
+
const ws = yield* WorkspaceMutations;
|
|
53
|
+
const trimmed = args.source.trim();
|
|
54
|
+
const env = yield* parseMcpEnvInputs(args.env);
|
|
55
|
+
const parsed = parseRegistryInstallTarget(trimmed, {
|
|
56
|
+
expectedType: "mcp-server",
|
|
57
|
+
allowBareName: true,
|
|
58
|
+
});
|
|
59
|
+
if (Result.isFailure(parsed)) {
|
|
60
|
+
switch (parsed.failure.kind) {
|
|
61
|
+
case "wrong-type":
|
|
62
|
+
return yield* installRefused({
|
|
63
|
+
category: "validation",
|
|
64
|
+
detail: "MCP server source must include /mcps/ segment",
|
|
65
|
+
suggestions: [{ description: "Use @owner/mcps/server-name format." }],
|
|
66
|
+
});
|
|
67
|
+
case "missing-name":
|
|
68
|
+
return yield* installRefused({
|
|
69
|
+
category: "not_found",
|
|
70
|
+
detail: "MCP server source must include a server name",
|
|
71
|
+
suggestions: [{ description: "Use @owner/mcps/server-name format." }],
|
|
72
|
+
});
|
|
73
|
+
default:
|
|
74
|
+
return yield* installRefused({
|
|
75
|
+
category: "usage",
|
|
76
|
+
detail: "MCP servers can only be installed from a registry",
|
|
77
|
+
suggestions: [{ description: REGISTRY_ONLY }],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const requestedLocalName = Option.getOrElse(args.localName, () => parsed.success.name);
|
|
82
|
+
if (parsed.success.kind === "registry") {
|
|
83
|
+
return {
|
|
84
|
+
owner: parsed.success.owner,
|
|
85
|
+
serverName: parsed.success.name,
|
|
86
|
+
localName: yield* decodeLocalName(requestedLocalName),
|
|
87
|
+
versionRange: Option.fromUndefinedOr(parsed.success.versionRange),
|
|
88
|
+
resolvedInput: trimmed,
|
|
89
|
+
force: args.force,
|
|
90
|
+
nonInteractive: args.nonInteractive,
|
|
91
|
+
env,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const owner = yield* ws.getConfiguredOwner().pipe(Effect.mapError((cause) => installRefused({
|
|
95
|
+
category: "internal",
|
|
96
|
+
detail: "Configured workspace owner could not be read",
|
|
97
|
+
cause,
|
|
98
|
+
})), Effect.flatMap(Option.match({
|
|
99
|
+
onNone: () => Effect.fail(installRefused({
|
|
100
|
+
category: "validation",
|
|
101
|
+
detail: `Cannot resolve bare MCP server name "${parsed.success.name}" without a configured owner`,
|
|
102
|
+
suggestions: [
|
|
103
|
+
{
|
|
104
|
+
description: "Use the fully-qualified `@owner/mcps/name` form, set `owner` in settings, or sign in.",
|
|
105
|
+
cmd: "axm login",
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
})),
|
|
109
|
+
onSome: Effect.succeed,
|
|
110
|
+
})));
|
|
111
|
+
return {
|
|
112
|
+
owner,
|
|
113
|
+
serverName: parsed.success.name,
|
|
114
|
+
localName: yield* decodeLocalName(requestedLocalName),
|
|
115
|
+
versionRange: Option.none(),
|
|
116
|
+
resolvedInput: `${owner}/mcps/${parsed.success.name}`,
|
|
117
|
+
force: args.force,
|
|
118
|
+
nonInteractive: args.nonInteractive,
|
|
119
|
+
env,
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* Decide which local name may own the connection and which version constraint
|
|
124
|
+
* every origin referencing the same registry server can agree on.
|
|
125
|
+
*/
|
|
126
|
+
export const resolveMcpServerSourceRequest = Effect.fn("InstallExtensions.resolveMcpSource")(function* (request) {
|
|
127
|
+
const ws = yield* WorkspaceMutations;
|
|
128
|
+
const source = yield* resolveSource(request.resolvedInput).pipe(Effect.mapError((cause) => installRefused({
|
|
129
|
+
category: "validation",
|
|
130
|
+
detail: `Invalid source: ${cause.message}`,
|
|
131
|
+
suggestions: [{ description: REGISTRY_ONLY }],
|
|
132
|
+
cause,
|
|
133
|
+
})));
|
|
134
|
+
if (source.type !== "registry") {
|
|
135
|
+
return yield* installRefused({
|
|
136
|
+
category: "usage",
|
|
137
|
+
detail: "MCP servers can only be installed from a registry",
|
|
138
|
+
suggestions: [{ description: "Use a registry source: @owner/mcps/server-name" }],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const identity = mcpRegistryResolutionKey({
|
|
142
|
+
authority: source.location,
|
|
143
|
+
owner: request.owner,
|
|
144
|
+
name: request.serverName,
|
|
145
|
+
});
|
|
146
|
+
const graph = yield* ws.getDesiredStateGraph().pipe(Effect.mapError((cause) => installRefused({
|
|
147
|
+
category: "internal",
|
|
148
|
+
detail: "Desired MCP state could not be read",
|
|
149
|
+
cause,
|
|
150
|
+
})));
|
|
151
|
+
const existingLocalNode = graph.nodes.find((node) => node.type === "mcp-server" && node.name === request.localName);
|
|
152
|
+
if (existingLocalNode !== undefined &&
|
|
153
|
+
(existingLocalNode.authority === "inline" || existingLocalNode.identity !== identity)) {
|
|
154
|
+
return yield* installRefused({
|
|
155
|
+
category: "conflict",
|
|
156
|
+
detail: `Local MCP name "${request.localName}" is already owned by a different source`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
const closure = graph.mcpSourceClosures.find((candidate) => candidate.identity === identity);
|
|
160
|
+
const retainedConstraints = (closure?.origins ?? []).flatMap((origin) => {
|
|
161
|
+
if (origin.constraint === undefined)
|
|
162
|
+
return [];
|
|
163
|
+
if (origin.type === "settings" && origin.localName === request.localName)
|
|
164
|
+
return [];
|
|
165
|
+
return [origin.constraint];
|
|
166
|
+
});
|
|
167
|
+
const requestedConstraints = Option.match(request.versionRange, {
|
|
168
|
+
onNone: () => retainedConstraints,
|
|
169
|
+
onSome: (range) => [...retainedConstraints, range],
|
|
170
|
+
});
|
|
171
|
+
const combinedConstraint = intersectVersionConstraints(requestedConstraints);
|
|
172
|
+
if (requestedConstraints.length > 0 && combinedConstraint === undefined) {
|
|
173
|
+
const contributors = (closure?.origins ?? [])
|
|
174
|
+
.filter((origin) => origin.constraint !== undefined)
|
|
175
|
+
.map((origin) => origin.type === "settings"
|
|
176
|
+
? `${origin.localName ?? "settings"}:${origin.constraint}`
|
|
177
|
+
: `${origin.pack}:${origin.constraint}`);
|
|
178
|
+
return yield* installRefused({
|
|
179
|
+
category: "conflict",
|
|
180
|
+
detail: `MCP source constraints do not intersect for ${request.owner}/mcps/${request.serverName}: ${[
|
|
181
|
+
...contributors,
|
|
182
|
+
`${request.localName}:${Option.getOrElse(request.versionRange, () => "*")}`,
|
|
183
|
+
].join(", ")}`,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
source,
|
|
188
|
+
owner: request.owner,
|
|
189
|
+
serverName: request.serverName,
|
|
190
|
+
versionRange: combinedConstraint === undefined ? Option.none() : Option.some(combinedConstraint),
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
/** Discover the MCP server the resolved request names. */
|
|
194
|
+
export const discoverMcpServerRefs = Effect.fn("InstallExtensions.discoverMcpServers")(function* (request) {
|
|
195
|
+
const sources = yield* SourceHostProviders;
|
|
196
|
+
const refs = yield* sources
|
|
197
|
+
.find(request.source, {
|
|
198
|
+
names: [request.serverName],
|
|
199
|
+
type: "mcp-server",
|
|
200
|
+
owner: Option.some(request.owner),
|
|
201
|
+
versionRange: request.versionRange,
|
|
202
|
+
})
|
|
203
|
+
.pipe(Effect.mapError((cause) => installRefused({
|
|
204
|
+
category: "network",
|
|
205
|
+
detail: "MCP server could not be fetched from registry",
|
|
206
|
+
suggestions: [{ description: "Verify the server name and registry configuration." }],
|
|
207
|
+
cause,
|
|
208
|
+
})));
|
|
209
|
+
return refs.filter((ref) => ref.type === "mcp-server");
|
|
210
|
+
});
|
|
211
|
+
/** Settle the connection this request installs, or refuse when nothing matched. */
|
|
212
|
+
export const finalizeMcpServerInstallIntent = Effect.fn("InstallExtensions.finalizeMcpIntent")(function* (request, refs) {
|
|
213
|
+
const ws = yield* WorkspaceMutations;
|
|
214
|
+
const [ref] = refs;
|
|
215
|
+
if (ref === undefined) {
|
|
216
|
+
const hosts = yield* ws.getRegistrySourceHosts().pipe(Effect.mapError((cause) => installRefused({
|
|
217
|
+
category: "internal",
|
|
218
|
+
detail: "Configured registry hosts could not be read",
|
|
219
|
+
cause,
|
|
220
|
+
})));
|
|
221
|
+
const loginSuggestions = yield* registryLoginSuggestions(hosts.map((host) => host.location.href));
|
|
222
|
+
return yield* installRefused({
|
|
223
|
+
category: "not_found",
|
|
224
|
+
detail: `MCP server "${request.serverName}" not found in registry`,
|
|
225
|
+
suggestions: [
|
|
226
|
+
{ description: "Verify the server name and check available MCP servers." },
|
|
227
|
+
...loginSuggestions,
|
|
228
|
+
],
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
ref,
|
|
233
|
+
localName: request.localName,
|
|
234
|
+
versionRange: request.versionRange,
|
|
235
|
+
force: request.force,
|
|
236
|
+
nonInteractive: request.nonInteractive,
|
|
237
|
+
env: request.env,
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
/** The closure a settled MCP intent becomes. */
|
|
241
|
+
export const planMcpServerInstall = Effect.fn("InstallExtensions.planMcpServer")(function* (intent) {
|
|
242
|
+
const ws = yield* WorkspaceMutations;
|
|
243
|
+
// A user-scope workspace can only hold an MCP configuration when every
|
|
244
|
+
// configured agent has a user-scope MCP config target to write into.
|
|
245
|
+
if (ws.scope === "user") {
|
|
246
|
+
const configuredAgents = yield* ws.getConfiguredAgents().pipe(Effect.mapError((cause) => installRefused({
|
|
247
|
+
category: "internal",
|
|
248
|
+
detail: "Configured agents could not be read",
|
|
249
|
+
cause,
|
|
250
|
+
})));
|
|
251
|
+
const refused = configuredAgents.flatMap((agentId) => {
|
|
252
|
+
if (!isConfigurableAgentId(agentId)) {
|
|
253
|
+
return [`${agentId}: no MCP capability catalog entry`];
|
|
254
|
+
}
|
|
255
|
+
const capability = CONFIGURABLE_AGENTS_BY_ID[agentId].capabilities["mcp-server"];
|
|
256
|
+
if (capability.axm.writer === null || !("transports" in capability.native)) {
|
|
257
|
+
return [`${agentId}: no MCP config support`];
|
|
258
|
+
}
|
|
259
|
+
return capability.axm.writer.config.targets.some((target) => target.scope === ws.scope)
|
|
260
|
+
? []
|
|
261
|
+
: [`${agentId}: no ${ws.scope} MCP config target`];
|
|
262
|
+
});
|
|
263
|
+
if (refused.length > 0) {
|
|
264
|
+
return yield* installRefused({
|
|
265
|
+
category: "validation",
|
|
266
|
+
detail: `Cannot install MCP servers in user scope for the configured agent placement: ${refused.join("; ")}`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
_tag: "Plan",
|
|
272
|
+
name: "Install MCP server",
|
|
273
|
+
description: Option.some(`Install MCP server ${intent.localName}`),
|
|
274
|
+
presentation: operationPresentation({ imperative: "install", past: "Installed", gerund: "Installing" }, "mcp-server"),
|
|
275
|
+
jobs: [
|
|
276
|
+
{
|
|
277
|
+
concurrency: 1,
|
|
278
|
+
steps: [
|
|
279
|
+
{
|
|
280
|
+
key: `mcp-server:${intent.localName}`,
|
|
281
|
+
label: intent.localName,
|
|
282
|
+
readiness: "ready",
|
|
283
|
+
run: installMcpServer({
|
|
284
|
+
name: "install-mcp-server",
|
|
285
|
+
args: {
|
|
286
|
+
ref: intent.ref,
|
|
287
|
+
localName: intent.localName,
|
|
288
|
+
nonInteractive: intent.nonInteractive,
|
|
289
|
+
force: intent.force,
|
|
290
|
+
versionRange: intent.versionRange,
|
|
291
|
+
skipSettings: Option.none(),
|
|
292
|
+
env: Option.some(intent.env ?? {}),
|
|
293
|
+
},
|
|
294
|
+
}).pipe(Effect.mapError(lifecycleStepFailure)),
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @experimental This API is unstable and may change without notice.
|
|
5
5
|
*/
|
|
6
|
+
import { NativeWriteAuthority } from "@agentxm/agent-integration";
|
|
6
7
|
import * as Effect from "effect/Effect";
|
|
7
8
|
import * as FileSystem from "effect/FileSystem";
|
|
8
9
|
import * as Path from "effect/Path";
|
|
9
|
-
import { CodingAgentRepository } from "@agentxm/
|
|
10
|
+
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
10
11
|
import type { StepFailure } from "@agentxm/workspace-operations";
|
|
11
12
|
import type { JobStepResult, Operation } from "@agentxm/workspace-operations";
|
|
12
13
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
13
|
-
import {
|
|
14
|
+
import { WorkspaceTransactionScope } from "@agentxm/workspace-transactions";
|
|
15
|
+
import { StepFailureConversion } from "../../step-failure-conversion.js";
|
|
14
16
|
export type DisableMcpServerOperation = Operation<"disable-mcp-server", {
|
|
15
17
|
readonly serverName: string;
|
|
16
18
|
}>;
|
|
17
|
-
export declare const disableMcpServer: (op: DisableMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | CodingAgentRepository |
|
|
19
|
+
export declare const disableMcpServer: (op: DisableMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | WorkspaceTransactionScope | CodingAgentRepository | NativeWriteAuthority | StepFailureConversion>;
|
|
18
20
|
//# sourceMappingURL=disable.d.ts.map
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @experimental This API is unstable and may change without notice.
|
|
5
5
|
*/
|
|
6
|
+
import { NativeWriteAuthority } from "@agentxm/agent-integration";
|
|
6
7
|
import * as Effect from "effect/Effect";
|
|
7
8
|
import * as FileSystem from "effect/FileSystem";
|
|
8
9
|
import * as Path from "effect/Path";
|
|
9
|
-
import { CodingAgentRepository } from "@agentxm/
|
|
10
|
+
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
10
11
|
import { appendWarningsToMessage } from "@agentxm/workspace-operations";
|
|
11
12
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
12
|
-
import {
|
|
13
|
+
import { WorkspaceTransactionScope, runWorkspaceTransaction, } from "@agentxm/workspace-transactions";
|
|
14
|
+
import { agentConfigTargets, mcpServerArtifact, mcpSettingsTarget, } from "@agentxm/extension-materialization";
|
|
13
15
|
import { mcpSyncWarnings, requireSuccessfulMcpSync } from "./sync-outcome.js";
|
|
14
|
-
import {
|
|
16
|
+
import { StepFailureConversion, withAdaptedStepFailures } from "../../step-failure-conversion.js";
|
|
15
17
|
import { ExtensionLifecycleFailed } from "../../errors.js";
|
|
16
18
|
export const disableMcpServer = (op) => Effect.gen(function* () {
|
|
17
19
|
const fs = yield* FileSystem.FileSystem;
|
|
@@ -27,7 +29,7 @@ export const disableMcpServer = (op) => Effect.gen(function* () {
|
|
|
27
29
|
});
|
|
28
30
|
}
|
|
29
31
|
const agents = yield* agentRepo.getConfiguredAgents();
|
|
30
|
-
const outcomes = yield*
|
|
32
|
+
const outcomes = yield* runWorkspaceTransaction({
|
|
31
33
|
transition: Effect.gen(function* () {
|
|
32
34
|
const synced = yield* Effect.forEach(agents, (agent) => agent.removeMcpServer({
|
|
33
35
|
workspaceRoot: ws.baseDir,
|
|
@@ -6,13 +6,15 @@
|
|
|
6
6
|
import * as FileSystem from "effect/FileSystem";
|
|
7
7
|
import * as Path from "effect/Path";
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
|
-
import { CodingAgentRepository } from "@agentxm/
|
|
9
|
+
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
10
|
+
import { NativeWriteAuthority } from "@agentxm/agent-integration";
|
|
10
11
|
import type { StepFailure } from "@agentxm/workspace-operations";
|
|
11
12
|
import type { JobStepResult, Operation } from "@agentxm/workspace-operations";
|
|
12
13
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
13
|
-
import {
|
|
14
|
+
import { WorkspaceTransactionScope } from "@agentxm/workspace-transactions";
|
|
15
|
+
import { StepFailureConversion } from "../../step-failure-conversion.js";
|
|
14
16
|
export type EnableMcpServerOperation = Operation<"enable-mcp-server", {
|
|
15
17
|
readonly serverName: string;
|
|
16
18
|
}>;
|
|
17
|
-
export declare const enableMcpServer: (op: EnableMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | CodingAgentRepository |
|
|
19
|
+
export declare const enableMcpServer: (op: EnableMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | WorkspaceTransactionScope | CodingAgentRepository | NativeWriteAuthority | StepFailureConversion>;
|
|
18
20
|
//# sourceMappingURL=enable.d.ts.map
|
|
@@ -7,14 +7,16 @@ import * as FileSystem from "effect/FileSystem";
|
|
|
7
7
|
import * as Path from "effect/Path";
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
9
|
import * as Option from "effect/Option";
|
|
10
|
-
import { CodingAgentRepository,
|
|
10
|
+
import { CodingAgentRepository, applyProjectionPlansWithResults, planSingletonProjection, } from "@agentxm/workspace-projection";
|
|
11
|
+
import { NativeWriteAuthority, syncInlineMcpServerToAgents } from "@agentxm/agent-integration";
|
|
11
12
|
import { normalizeHandle, parseExtensionFqnParts, } from "@agentxm/extension-model/unstable/extensions";
|
|
12
13
|
import { appendWarningsToMessage } from "@agentxm/workspace-operations";
|
|
13
14
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
14
|
-
import {
|
|
15
|
+
import { WorkspaceTransactionScope, runWorkspaceTransaction, } from "@agentxm/workspace-transactions";
|
|
16
|
+
import { agentConfigTargets, mcpServerArtifact, mcpSettingsTarget, } from "@agentxm/extension-materialization";
|
|
15
17
|
import { usableAcceptedCanonicalObservation } from "@agentxm/workspace-state";
|
|
16
18
|
import { mcpSyncWarnings, requireSuccessfulMcpSync } from "./sync-outcome.js";
|
|
17
|
-
import {
|
|
19
|
+
import { StepFailureConversion, withAdaptedStepFailures } from "../../step-failure-conversion.js";
|
|
18
20
|
import { ExtensionLifecycleFailed } from "../../errors.js";
|
|
19
21
|
const enableArtifact = (args) => {
|
|
20
22
|
return mcpServerArtifact({
|
|
@@ -39,7 +41,7 @@ export const enableMcpServer = (op) => Effect.gen(function* () {
|
|
|
39
41
|
}
|
|
40
42
|
if (entry.kind === "inline") {
|
|
41
43
|
const agentIds = yield* ws.getConfiguredAgents();
|
|
42
|
-
const outcomes = yield*
|
|
44
|
+
const outcomes = yield* runWorkspaceTransaction({
|
|
43
45
|
transition: Effect.gen(function* () {
|
|
44
46
|
const synced = yield* syncInlineMcpServerToAgents(agentIds, {
|
|
45
47
|
workspaceRoot: ws.baseDir,
|
|
@@ -115,7 +117,7 @@ export const enableMcpServer = (op) => Effect.gen(function* () {
|
|
|
115
117
|
const owner = trustedIdentity?.type === "mcp-server" ? trustedIdentity.owner : normalizeHandle("@local");
|
|
116
118
|
const resolvedVersion = accepted?.type === "registry" ? accepted.resolvedVersion : "0.0.0";
|
|
117
119
|
const agents = yield* agentRepo.getConfiguredAgents();
|
|
118
|
-
const outcomes = yield*
|
|
120
|
+
const outcomes = yield* runWorkspaceTransaction({
|
|
119
121
|
transition: Effect.gen(function* () {
|
|
120
122
|
const synced = yield* applyProjectionPlansWithResults(agents.map((agent) => planSingletonProjection({
|
|
121
123
|
unitId: "mcp-server:native-config-entry",
|
|
@@ -141,7 +143,7 @@ export const enableMcpServer = (op) => Effect.gen(function* () {
|
|
|
141
143
|
enabled: true,
|
|
142
144
|
configValues: entry.env,
|
|
143
145
|
});
|
|
144
|
-
})
|
|
146
|
+
}),
|
|
145
147
|
},
|
|
146
148
|
})));
|
|
147
149
|
yield* requireSuccessfulMcpSync(op.args.serverName, agents.map((agent, index) => ({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
-
import type { McpServerSyncOutcome } from "@agentxm/
|
|
2
|
+
import type { McpServerSyncOutcome } from "@agentxm/agent-integration";
|
|
3
3
|
import { ExtensionLifecycleFailed } from "../../errors.js";
|
|
4
4
|
export interface AgentMcpSyncOutcome {
|
|
5
5
|
readonly agentId: string;
|
|
@@ -11,11 +11,13 @@ import * as FileSystem from "effect/FileSystem";
|
|
|
11
11
|
import * as Path from "effect/Path";
|
|
12
12
|
import * as Effect from "effect/Effect";
|
|
13
13
|
import * as Option from "effect/Option";
|
|
14
|
-
import {
|
|
14
|
+
import { NativeWriteAuthority } from "@agentxm/agent-integration";
|
|
15
|
+
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
15
16
|
import type { StepFailure } from "@agentxm/workspace-operations";
|
|
16
17
|
import type { JobStepResult, Operation } from "@agentxm/workspace-operations";
|
|
17
18
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
18
|
-
import {
|
|
19
|
+
import { McpSecretStore } from "@agentxm/extension-materialization";
|
|
20
|
+
import { StepFailureConversion } from "../../step-failure-conversion.js";
|
|
19
21
|
/**
|
|
20
22
|
* Args for the uninstall-mcp-server operation.
|
|
21
23
|
*/
|
|
@@ -37,5 +39,5 @@ export type UninstallMcpServerOperation = Operation<"uninstall-mcp-server", Unin
|
|
|
37
39
|
* 2. Remove canonical directory from disk (if exists)
|
|
38
40
|
* 3. Remove settings and accepted resolution
|
|
39
41
|
*/
|
|
40
|
-
export declare const uninstallMcpServer: (op: UninstallMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | CodingAgentRepository |
|
|
42
|
+
export declare const uninstallMcpServer: (op: UninstallMcpServerOperation) => Effect.Effect<JobStepResult, StepFailure, FileSystem.FileSystem | Path.Path | WorkspaceMutations | CodingAgentRepository | NativeWriteAuthority | McpSecretStore | StepFailureConversion>;
|
|
41
43
|
//# sourceMappingURL=uninstall.d.ts.map
|
|
@@ -12,15 +12,15 @@ import * as Path from "effect/Path";
|
|
|
12
12
|
import * as Array from "effect/Array";
|
|
13
13
|
import * as Effect from "effect/Effect";
|
|
14
14
|
import * as Option from "effect/Option";
|
|
15
|
-
import {
|
|
15
|
+
import { NativeWriteAuthority } from "@agentxm/agent-integration";
|
|
16
|
+
import { CodingAgentRepository } from "@agentxm/workspace-projection";
|
|
16
17
|
import { appendWarningsToMessage } from "@agentxm/workspace-operations";
|
|
17
18
|
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
18
19
|
import { removeIfExists } from "@agentxm/workspace-state";
|
|
19
20
|
import { acceptedCanonicalObservation, acceptedLockedCanonicalPath, removableAcceptedCanonicalPath, } from "@agentxm/workspace-state";
|
|
20
|
-
import { agentConfigTarget, mcpServerArtifact, mcpSettingsTarget } from "
|
|
21
|
-
import {
|
|
21
|
+
import { agentConfigTarget, collectSecretInputNames, deleteMcpSecrets, mcpServerArtifact, mcpSettingsTarget, readMcpServerManifest, McpSecretStore, } from "@agentxm/extension-materialization";
|
|
22
|
+
import { StepFailureConversion, withAdaptedStepFailures } from "../../step-failure-conversion.js";
|
|
22
23
|
import { ExtensionLifecycleFailed } from "../../errors.js";
|
|
23
|
-
import { collectSecretInputNames, deleteMcpSecrets, readMcpServerManifest } from "./install.js";
|
|
24
24
|
const REQUIRED_AGENT_IDS = new Set([
|
|
25
25
|
"claude-code",
|
|
26
26
|
"opencode",
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uninstalling an MCP connection.
|
|
3
|
+
*
|
|
4
|
+
* Removing a connection also removes the secrets it stored in the operating
|
|
5
|
+
* system keychain, because those inputs exist only for that connection. A
|
|
6
|
+
* keychain that refuses the deletion does not fail the removal — AXM state is
|
|
7
|
+
* already applied — but it is reported, because a credential left behind is
|
|
8
|
+
* something the operator has to finish by hand.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as FileSystem from "effect/FileSystem";
|
|
14
|
+
import * as Path from "effect/Path";
|
|
15
|
+
import { McpServerManager } from "@agentxm/extension-materialization";
|
|
16
|
+
import { type Plan } from "@agentxm/workspace-operations";
|
|
17
|
+
import type { ExtensionLifecycleFailed } from "../../errors.js";
|
|
18
|
+
import type { InstallStepRequirements } from "../../install/vocabulary.js";
|
|
19
|
+
import type { McpServerUninstallIntent } from "../../uninstall/vocabulary.js";
|
|
20
|
+
/** One local connection name is removed at a time. */
|
|
21
|
+
export declare const parseMcpServerUninstallRequest: (selector: string) => McpServerUninstallIntent;
|
|
22
|
+
/** The closure a settled MCP removal becomes. */
|
|
23
|
+
export declare const planMcpServerUninstall: (intent: McpServerUninstallIntent) => Effect.Effect<Plan<InstallStepRequirements>, ExtensionLifecycleFailed, InstallStepRequirements | McpServerManager | FileSystem.FileSystem | Path.Path>;
|
|
24
|
+
//# sourceMappingURL=plan.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uninstalling an MCP connection.
|
|
3
|
+
*
|
|
4
|
+
* Removing a connection also removes the secrets it stored in the operating
|
|
5
|
+
* system keychain, because those inputs exist only for that connection. A
|
|
6
|
+
* keychain that refuses the deletion does not fail the removal — AXM state is
|
|
7
|
+
* already applied — but it is reported, because a credential left behind is
|
|
8
|
+
* something the operator has to finish by hand.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as FileSystem from "effect/FileSystem";
|
|
14
|
+
import * as Option from "effect/Option";
|
|
15
|
+
import * as Path from "effect/Path";
|
|
16
|
+
import { McpServerManager, buildUninstallOperation, collectSecretInputNames, deleteMcpSecrets, mcpServerArtifact, mcpSourceTarget, readMcpServerManifest, } from "@agentxm/extension-materialization";
|
|
17
|
+
import { appendWarningsToMessage, } from "@agentxm/workspace-operations";
|
|
18
|
+
import { WorkspaceMutations, acceptedLockedCanonicalPath, } from "@agentxm/workspace-state";
|
|
19
|
+
import { lifecycleStepFailure } from "../../step-failure.js";
|
|
20
|
+
import { makeWorkspaceRetentionPolicy } from "../../uninstall/retention-policy.js";
|
|
21
|
+
import { workspaceLockfilePath, workspaceSettingsPath } from "../../workspace-paths.js";
|
|
22
|
+
/** One local connection name is removed at a time. */
|
|
23
|
+
export const parseMcpServerUninstallRequest = (selector) => ({
|
|
24
|
+
targets: [{ type: "mcp-server", name: selector.trim() }],
|
|
25
|
+
});
|
|
26
|
+
/** The closure a settled MCP removal becomes. */
|
|
27
|
+
export const planMcpServerUninstall = Effect.fn("UninstallExtensions.planMcpServers")(function* (intent) {
|
|
28
|
+
const ws = yield* WorkspaceMutations;
|
|
29
|
+
const mcpServerManager = yield* McpServerManager;
|
|
30
|
+
const path = yield* Path.Path;
|
|
31
|
+
const retentionPolicy = makeWorkspaceRetentionPolicy(ws);
|
|
32
|
+
const steps = intent.targets.map((target) => {
|
|
33
|
+
const step = buildUninstallOperation(mcpServerManager, retentionPolicy, {
|
|
34
|
+
toStepFailure: lifecycleStepFailure,
|
|
35
|
+
target,
|
|
36
|
+
});
|
|
37
|
+
if (step.readiness !== "ready")
|
|
38
|
+
return step;
|
|
39
|
+
return {
|
|
40
|
+
...step,
|
|
41
|
+
run: Effect.gen(function* () {
|
|
42
|
+
const graph = yield* ws
|
|
43
|
+
.getDesiredStateGraph()
|
|
44
|
+
.pipe(Effect.catch(() => Effect.succeed(undefined)));
|
|
45
|
+
const desiredNode = graph?.nodes.find((node) => node.type === "mcp-server" && node.name === target.name);
|
|
46
|
+
const lockEntry = Option.getOrUndefined(yield* ws
|
|
47
|
+
.getLockedMcpServerForConnection(target.name)
|
|
48
|
+
.pipe(Effect.catch(() => Effect.succeed(Option.none()))));
|
|
49
|
+
const canonicalPath = yield* acceptedLockedCanonicalPath({
|
|
50
|
+
workspace: ws,
|
|
51
|
+
type: "mcp-server",
|
|
52
|
+
name: target.name,
|
|
53
|
+
}).pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
54
|
+
const manifest = yield* Option.match(canonicalPath, {
|
|
55
|
+
onNone: () => Effect.succeed(Option.none()),
|
|
56
|
+
onSome: (root) => readMcpServerManifest(root),
|
|
57
|
+
});
|
|
58
|
+
const result = yield* step.run;
|
|
59
|
+
if (result.result !== "success")
|
|
60
|
+
return result;
|
|
61
|
+
const unchanged = result.disposition === "unchanged";
|
|
62
|
+
const secretNames = Option.match(manifest, {
|
|
63
|
+
onNone: () => new Set(),
|
|
64
|
+
onSome: collectSecretInputNames,
|
|
65
|
+
});
|
|
66
|
+
const secretDeletionWarnings = unchanged || desiredNode === undefined || desiredNode.authority === "inline"
|
|
67
|
+
? []
|
|
68
|
+
: (yield* deleteMcpSecrets({
|
|
69
|
+
scopeRoot: path.resolve(ws.baseDir),
|
|
70
|
+
localName: target.name,
|
|
71
|
+
sourceIdentity: desiredNode.identity,
|
|
72
|
+
}, secretNames)).flatMap((outcome) => outcome._tag === "failed"
|
|
73
|
+
? [
|
|
74
|
+
`${outcome.inputName} could not be deleted from the system keychain; AXM state was applied and credential cleanup is required`,
|
|
75
|
+
]
|
|
76
|
+
: []);
|
|
77
|
+
const sourceTarget = lockEntry?.type === "registry"
|
|
78
|
+
? mcpSourceTarget(ws.scope, lockEntry, "removed")
|
|
79
|
+
: undefined;
|
|
80
|
+
return {
|
|
81
|
+
...result,
|
|
82
|
+
message: appendWarningsToMessage(result.message, secretDeletionWarnings),
|
|
83
|
+
...(secretDeletionWarnings.length === 0
|
|
84
|
+
? {}
|
|
85
|
+
: { warnings: [...(result.warnings ?? []), ...secretDeletionWarnings] }),
|
|
86
|
+
artifact: mcpServerArtifact({
|
|
87
|
+
lockEntry,
|
|
88
|
+
scope: ws.scope,
|
|
89
|
+
change: unchanged ? "unchanged" : "removed",
|
|
90
|
+
targets: unchanged
|
|
91
|
+
? []
|
|
92
|
+
: [
|
|
93
|
+
{ path: workspaceLockfilePath(ws.scope), change: "updated" },
|
|
94
|
+
{ path: workspaceSettingsPath(ws.scope), change: "updated" },
|
|
95
|
+
...(sourceTarget === undefined ? [] : [sourceTarget]),
|
|
96
|
+
],
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
99
|
+
}),
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
_tag: "Plan",
|
|
104
|
+
name: "Uninstall MCP server",
|
|
105
|
+
description: Option.some(`Uninstall MCP server ${intent.targets.map((target) => target.name).join(", ")}`),
|
|
106
|
+
jobs: [{ concurrency: 1, steps }],
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a pack member's acquired package sits, and what an install changed
|
|
3
|
+
* about it. Both the member step and the pack planner report the same
|
|
4
|
+
* artifact for the same ref, so a preview and its apply name one path.
|
|
5
|
+
*
|
|
6
|
+
* @experimental This API is unstable and may change without notice.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/extension-ref";
|
|
9
|
+
import { type ExtensionType, type ExtensionTypePlural } from "@agentxm/extension-model/unstable/extensions";
|
|
10
|
+
import type { JobStepArtifact } from "@agentxm/workspace-operations";
|
|
11
|
+
/** The registry directory segment a type's acquired packages live under. */
|
|
12
|
+
export declare const registryPluralSegment: (type: ExtensionType) => ExtensionTypePlural;
|
|
13
|
+
/** Workspace-relative path of a ref's acquired (or authored) package. */
|
|
14
|
+
export declare const registrySourcePath: (ref: ExtensionRef, scope: JobStepArtifact["scope"]) => string;
|
|
15
|
+
/** The artifact one acquired pack member reports. */
|
|
16
|
+
export declare const registrySourceArtifact: (args: {
|
|
17
|
+
readonly ref: ExtensionRef;
|
|
18
|
+
readonly scope: JobStepArtifact["scope"];
|
|
19
|
+
readonly installedBefore: boolean;
|
|
20
|
+
}) => JobStepArtifact;
|
|
21
|
+
//# sourceMappingURL=artifact.d.ts.map
|