@agentxm/extension-materialization 0.29.2 → 0.30.1
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/hooks/manager.d.ts +0 -5
- package/dist/src/hooks/manager.js +73 -36
- package/dist/src/index.d.ts +1 -6
- package/dist/src/index.js +0 -9
- package/dist/src/knowledge/manager.d.ts +0 -1
- package/dist/src/knowledge/manager.js +36 -29
- package/dist/src/manager-contract.d.ts +16 -18
- package/dist/src/manager-registry.d.ts +2 -3
- package/dist/src/managers.d.ts +22 -3
- package/dist/src/managers.js +0 -13
- package/dist/src/mcps/manager.js +84 -44
- package/dist/src/packs/manager.js +21 -18
- package/dist/src/rules/manager.d.ts +0 -5
- package/dist/src/rules/manager.js +22 -32
- package/dist/src/skills/errors.d.ts +2 -1
- package/dist/src/skills/manager.js +45 -53
- package/dist/src/skills/materialization.d.ts +2 -2
- package/dist/src/skills/skill-artifact.d.ts +5 -1
- package/dist/src/subagents/manager.js +31 -52
- package/dist/src/testing.d.ts +0 -66
- package/dist/src/testing.js +1 -89
- package/package.json +19 -22
- package/dist/src/desired-state/errors.d.ts +0 -22
- package/dist/src/desired-state/errors.js +0 -22
- package/dist/src/desired-state/retained-materialization.d.ts +0 -58
- package/dist/src/desired-state/retained-materialization.js +0 -119
- package/dist/src/extensions/operations.d.ts +0 -252
- package/dist/src/extensions/operations.js +0 -631
- package/dist/src/mcps/authored-materialization.d.ts +0 -28
- package/dist/src/mcps/authored-materialization.js +0 -34
- package/dist/src/mcps/install-operation.d.ts +0 -92
- package/dist/src/mcps/install-operation.js +0 -557
package/dist/src/mcps/manager.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { usableAcceptedCanonical } from "@agentxm/workspace-state";
|
|
2
|
+
import { LifecyclePostconditionViolated } from "../extensions/errors.js";
|
|
1
3
|
/**
|
|
2
4
|
* MCP server extension manager service.
|
|
3
5
|
*
|
|
@@ -12,10 +14,10 @@ import * as Effect from "effect/Effect";
|
|
|
12
14
|
import * as Layer from "effect/Layer";
|
|
13
15
|
import * as Option from "effect/Option";
|
|
14
16
|
import { McpInstallStateMissing, McpRegistryOnlyInstall } from "./errors.js";
|
|
15
|
-
import { applyProjectionPlans, planSingletonProjection } from "@agentxm/workspace-projection";
|
|
17
|
+
import { applyProjectionPlans, inspectMcpServerAcrossAgents, planSingletonProjection, } from "@agentxm/workspace-projection";
|
|
16
18
|
import { McpConfigIoFailed, removeMcpServerFromManifest } from "@agentxm/agent-integration";
|
|
17
19
|
import { NO_MATERIALIZATION_OBSERVATION } from "../manager-contract.js";
|
|
18
|
-
import { McpServerManager } from "../managers.js";
|
|
20
|
+
import { McpServerManager, } from "../managers.js";
|
|
19
21
|
import { configuredMcpServersToDiskRefs } from "../extensions/materializable-from-disk.js";
|
|
20
22
|
import { mcpRegistryResolutionKey, WorkspaceMutations } from "@agentxm/workspace-state";
|
|
21
23
|
import { canReuseInstalledPackage } from "../extensions/canonical-directory.js";
|
|
@@ -159,12 +161,79 @@ export const McpServerManagerLive = Layer.effect(McpServerManager, Effect.gen(fu
|
|
|
159
161
|
});
|
|
160
162
|
const materializeUninstall = makeMaterializeRemoval(false);
|
|
161
163
|
const materializeDeactivate = makeMaterializeRemoval(true);
|
|
164
|
+
const configuredAgentOutcomesForEntry = Effect.fn("McpServerManager.configuredAgentOutcomesForEntry")(function* ({ name, entry, state, }) {
|
|
165
|
+
const configuredAgentIds = yield* ws.getConfiguredAgents();
|
|
166
|
+
const canonical = entry.kind === "inline"
|
|
167
|
+
? Option.none()
|
|
168
|
+
: (yield* acceptedCanonicalObservation({
|
|
169
|
+
workspace: ws,
|
|
170
|
+
type: "mcp-server",
|
|
171
|
+
name,
|
|
172
|
+
})).pipe(Option.flatMap(({ observation }) => Option.fromUndefinedOr(observation.path)));
|
|
173
|
+
const inspections = yield* inspectMcpServerAcrossAgents({
|
|
174
|
+
workspaceRoot: baseDir,
|
|
175
|
+
scope: ws.scope,
|
|
176
|
+
agentIds: configuredAgentIds,
|
|
177
|
+
serverName: name,
|
|
178
|
+
entry: { ...entry, enabled: true },
|
|
179
|
+
canonicalPaths: Option.match(canonical, { onNone: () => [], onSome: (value) => [value] }),
|
|
180
|
+
state,
|
|
181
|
+
});
|
|
182
|
+
return inspections.map((inspection) => ({
|
|
183
|
+
extensionType: "mcp-server",
|
|
184
|
+
name,
|
|
185
|
+
agentId: inspection.agentId,
|
|
186
|
+
outcome: inspection.status === "match"
|
|
187
|
+
? state
|
|
188
|
+
: inspection.status === "unsupported"
|
|
189
|
+
? "unsupported"
|
|
190
|
+
: inspection.status === "blocked"
|
|
191
|
+
? "blocked"
|
|
192
|
+
: "failed",
|
|
193
|
+
reasonCode: inspection.status === "match"
|
|
194
|
+
? "supported"
|
|
195
|
+
: inspection.status === "absent"
|
|
196
|
+
? "projection-missing"
|
|
197
|
+
: inspection.status === "drift"
|
|
198
|
+
? "stale-projection"
|
|
199
|
+
: `mcp-${inspection.status}`,
|
|
200
|
+
reason: inspection.reason ??
|
|
201
|
+
(inspection.status === "match"
|
|
202
|
+
? `${inspection.agentId} has a matching MCP projection.`
|
|
203
|
+
: inspection.status === "absent"
|
|
204
|
+
? `The expected ${inspection.agentId} projection is missing.`
|
|
205
|
+
: inspection.status === "drift"
|
|
206
|
+
? `The expected ${inspection.agentId} projection is stale.`
|
|
207
|
+
: `MCP projection status is ${inspection.status}.`),
|
|
208
|
+
...(inspection.path.length === 0 ? {} : { path: inspection.path }),
|
|
209
|
+
}));
|
|
210
|
+
});
|
|
211
|
+
const configuredAgentOutcomes = (state) => Effect.gen(function* () {
|
|
212
|
+
const entries = yield* ws.getConfiguredMcpServerEntries();
|
|
213
|
+
return (yield* Effect.forEach(Object.entries(entries).filter(([, entry]) => state === "projected" || entry.enabled), ([name, entry]) => configuredAgentOutcomesForEntry({ name, entry, state }), { concurrency: "unbounded" })).flat();
|
|
214
|
+
});
|
|
162
215
|
return {
|
|
163
216
|
type: "mcp-server",
|
|
164
217
|
isInstalled: Effect.fn("McpServerManager.isInstalled")(function* ({ target, }) {
|
|
165
218
|
return yield* isObservedInstalled(ws, "mcp-server", target.name);
|
|
166
219
|
}),
|
|
167
220
|
materializeInstall,
|
|
221
|
+
acquireCanonical: materializeInstall,
|
|
222
|
+
materializeRetained: ({ target }) => Effect.gen(function* () {
|
|
223
|
+
const canonical = yield* usableAcceptedCanonical({
|
|
224
|
+
workspace: ws,
|
|
225
|
+
type: "mcp-server",
|
|
226
|
+
name: target.name,
|
|
227
|
+
});
|
|
228
|
+
if (Option.isNone(canonical) || canonical.value.ref.type !== "mcp-server") {
|
|
229
|
+
return yield* new LifecyclePostconditionViolated({
|
|
230
|
+
postcondition: "materialize-observable",
|
|
231
|
+
targetType: "mcp-server",
|
|
232
|
+
targetName: target.name,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return yield* materializeInstall({ ref: canonical.value.ref });
|
|
236
|
+
}),
|
|
168
237
|
prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
|
|
169
238
|
workspace: ws,
|
|
170
239
|
type: "mcp-server",
|
|
@@ -187,9 +256,11 @@ export const McpServerManagerLive = Layer.effect(McpServerManager, Effect.gen(fu
|
|
|
187
256
|
}),
|
|
188
257
|
materializeUninstall,
|
|
189
258
|
materializeDeactivate,
|
|
190
|
-
|
|
259
|
+
configuredAgentOutcomes,
|
|
260
|
+
configuredAgentOutcomesForEntry,
|
|
261
|
+
acceptedResolution: ({ ref, materialization, }) => {
|
|
191
262
|
if (ref.refType !== "registry")
|
|
192
|
-
return Effect.
|
|
263
|
+
return Effect.succeed(Option.none());
|
|
193
264
|
const registryRef = ref;
|
|
194
265
|
return validateExactResolvedVersion(`mcpServers.${ref.server.name}.resolvedVersion`, registryRef.version).pipe(Effect.flatMap(() => {
|
|
195
266
|
const treeIntegrity = materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity));
|
|
@@ -197,56 +268,25 @@ export const McpServerManagerLive = Layer.effect(McpServerManager, Effect.gen(fu
|
|
|
197
268
|
return Effect.fail(new McpInstallStateMissing({ name: registryRef.server.name }));
|
|
198
269
|
}
|
|
199
270
|
const lockEntry = buildMcpServerLockEntry(registryRef, treeIntegrity.value);
|
|
200
|
-
return
|
|
201
|
-
|
|
202
|
-
resolutionKey: mcpRegistryResolutionKey({
|
|
271
|
+
return Effect.succeed(Option.some({
|
|
272
|
+
key: mcpRegistryResolutionKey({
|
|
203
273
|
authority: registryRef.source.location,
|
|
204
274
|
owner: registryRef.owner,
|
|
205
275
|
name: registryRef.server.name,
|
|
206
276
|
}),
|
|
207
|
-
lockEntry,
|
|
208
|
-
|
|
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"));
|
|
277
|
+
entry: lockEntry,
|
|
278
|
+
}));
|
|
279
|
+
}), Effect.withSpan("McpServerManager.acceptedResolution"));
|
|
238
280
|
},
|
|
239
|
-
|
|
281
|
+
withdrawnResolutionKeys: ({ materialization, }) => {
|
|
240
282
|
const removal = materialization.pipe(Option.flatMap((facts) => facts.removal));
|
|
241
283
|
if (Option.isNone(removal)) {
|
|
242
|
-
return Effect.
|
|
284
|
+
return Effect.succeed([]);
|
|
243
285
|
}
|
|
244
286
|
if (removal.value.retainShared || Option.isNone(removal.value.resolutionKey)) {
|
|
245
|
-
return Effect.
|
|
287
|
+
return Effect.succeed([]);
|
|
246
288
|
}
|
|
247
|
-
return
|
|
248
|
-
.removeMcpServerLock(removal.value.resolutionKey.value)
|
|
249
|
-
.pipe(Effect.withSpan("McpServerManager.removeLockfileEntry"));
|
|
289
|
+
return Effect.succeed([removal.value.resolutionKey.value]);
|
|
250
290
|
},
|
|
251
291
|
};
|
|
252
292
|
}));
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { usableAcceptedCanonical } from "@agentxm/workspace-state";
|
|
2
|
+
import { LifecyclePostconditionViolated } from "../extensions/errors.js";
|
|
1
3
|
/**
|
|
2
4
|
* Pack manager service.
|
|
3
5
|
*
|
|
@@ -145,6 +147,7 @@ export const PackManagerLive = Layer.effect(PackManager, Effect.gen(function* ()
|
|
|
145
147
|
return yield* isObservedInstalled(ws, "pack", target.name);
|
|
146
148
|
}),
|
|
147
149
|
materializeInstall,
|
|
150
|
+
acquireCanonical: materializeInstall,
|
|
148
151
|
prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
|
|
149
152
|
workspace: ws,
|
|
150
153
|
type: "pack",
|
|
@@ -161,29 +164,29 @@ export const PackManagerLive = Layer.effect(PackManager, Effect.gen(function* ()
|
|
|
161
164
|
}),
|
|
162
165
|
materializeUninstall,
|
|
163
166
|
materializeDeactivate,
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
materializeRetained: ({ target }) => Effect.gen(function* () {
|
|
168
|
+
const canonical = yield* usableAcceptedCanonical({
|
|
169
|
+
workspace: ws,
|
|
170
|
+
type: "pack",
|
|
171
|
+
name: target.name,
|
|
172
|
+
});
|
|
173
|
+
if (Option.isNone(canonical) || canonical.value.ref.type !== "pack") {
|
|
174
|
+
return yield* new LifecyclePostconditionViolated({
|
|
175
|
+
postcondition: "materialize-observable",
|
|
176
|
+
targetType: "pack",
|
|
177
|
+
targetName: target.name,
|
|
173
178
|
});
|
|
174
179
|
}
|
|
180
|
+
return yield* materializeDeactivate({ target });
|
|
175
181
|
}),
|
|
176
|
-
|
|
177
|
-
upsertLockfileEntry: Effect.fn("PackManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
|
|
182
|
+
acceptedResolution: Effect.fn("PackManager.acceptedResolution")(function* ({ ref, materialization, }) {
|
|
178
183
|
const args = yield* buildCurrentPackArgs(ref, Option.none(), materialization);
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
yield* ws.removePackLock(ref.pack.name);
|
|
184
|
-
}
|
|
184
|
+
return Option.map(args, ({ versionRange: _versionRange, ...entry }) => ({
|
|
185
|
+
key: ref.pack.name,
|
|
186
|
+
entry,
|
|
187
|
+
}));
|
|
185
188
|
}),
|
|
186
|
-
|
|
189
|
+
withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
|
|
187
190
|
};
|
|
188
191
|
}));
|
|
189
192
|
//# sourceMappingURL=manager.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { usableAcceptedCanonical } from "@agentxm/workspace-state";
|
|
2
|
+
import { LifecyclePostconditionViolated } from "../extensions/errors.js";
|
|
1
3
|
/**
|
|
2
4
|
* Rule manager service.
|
|
3
5
|
*
|
|
@@ -424,6 +426,22 @@ export const RuleManagerLive = Layer.effect(RuleManager, Effect.gen(function* ()
|
|
|
424
426
|
aggregateProjectionObservation: Ref.get(lastProjection),
|
|
425
427
|
isInstalled: ({ target }) => isObservedInstalled(ws, "rule", target.name).pipe(Effect.withSpan("RuleManager.isInstalled")),
|
|
426
428
|
materializeInstall,
|
|
429
|
+
acquireCanonical: materializeInstall,
|
|
430
|
+
materializeRetained: ({ target }) => Effect.gen(function* () {
|
|
431
|
+
const canonical = yield* usableAcceptedCanonical({
|
|
432
|
+
workspace: ws,
|
|
433
|
+
type: "rule",
|
|
434
|
+
name: target.name,
|
|
435
|
+
});
|
|
436
|
+
if (Option.isNone(canonical) || canonical.value.ref.type !== "rule") {
|
|
437
|
+
return yield* new LifecyclePostconditionViolated({
|
|
438
|
+
postcondition: "materialize-observable",
|
|
439
|
+
targetType: "rule",
|
|
440
|
+
targetName: target.name,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
return yield* materializeInstall({ ref: canonical.value.ref });
|
|
444
|
+
}),
|
|
427
445
|
prepareSourceTransition: ({ ref }) => provide(prepareAcceptedCanonicalTransition({
|
|
428
446
|
workspace: ws,
|
|
429
447
|
type: "rule",
|
|
@@ -448,45 +466,17 @@ export const RuleManagerLive = Layer.effect(RuleManager, Effect.gen(function* ()
|
|
|
448
466
|
}),
|
|
449
467
|
materializeUninstall,
|
|
450
468
|
materializeDeactivate,
|
|
451
|
-
|
|
452
|
-
const lockEntry = yield* buildLockEntry(ref, materialization);
|
|
453
|
-
if (Option.isNone(lockEntry)) {
|
|
454
|
-
yield* ws.setRuleEntry(ref.rule.name, {
|
|
455
|
-
source: "workspace",
|
|
456
|
-
enabled: true,
|
|
457
|
-
});
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
if (lockEntry.value.type === "registry") {
|
|
461
|
-
yield* validateExactResolvedVersion(`rules.${ref.rule.name}.resolvedVersion`, lockEntry.value.resolvedVersion);
|
|
462
|
-
}
|
|
463
|
-
yield* ws.setRule({
|
|
464
|
-
name: ref.rule.name,
|
|
465
|
-
lockEntry: lockEntry.value,
|
|
466
|
-
versionRange,
|
|
467
|
-
});
|
|
468
|
-
}),
|
|
469
|
-
removeSettingsEntry: Effect.fn("RuleManager.removeSettingsEntry")(function* ({ target }) {
|
|
470
|
-
yield* ws.removeRuleSettings(target.name);
|
|
471
|
-
}),
|
|
472
|
-
upsertLockfileEntry: Effect.fn("RuleManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
|
|
469
|
+
acceptedResolution: Effect.fn("RuleManager.acceptedResolution")(function* ({ ref, materialization, }) {
|
|
473
470
|
const lockEntry = yield* buildLockEntry(ref, materialization);
|
|
474
471
|
if (Option.isNone(lockEntry)) {
|
|
475
|
-
|
|
476
|
-
return;
|
|
472
|
+
return Option.none();
|
|
477
473
|
}
|
|
478
474
|
if (lockEntry.value.type === "registry") {
|
|
479
475
|
yield* validateExactResolvedVersion(`rules.${ref.rule.name}.resolvedVersion`, lockEntry.value.resolvedVersion);
|
|
480
476
|
}
|
|
481
|
-
|
|
482
|
-
name: ref.rule.name,
|
|
483
|
-
lockEntry: lockEntry.value,
|
|
484
|
-
versionRange: Option.none(),
|
|
485
|
-
});
|
|
486
|
-
}),
|
|
487
|
-
removeLockfileEntry: Effect.fn("RuleManager.removeLockfileEntry")(function* ({ target }) {
|
|
488
|
-
yield* ws.removeRuleLock(target.name);
|
|
477
|
+
return Option.some({ key: ref.rule.name, entry: lockEntry.value });
|
|
489
478
|
}),
|
|
479
|
+
withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
|
|
490
480
|
};
|
|
491
481
|
}));
|
|
492
482
|
//# sourceMappingURL=manager.js.map
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @experimental This API is unstable and may change without notice.
|
|
7
7
|
*/
|
|
8
|
-
import type { AxmSkillCompatibilityUnavailable
|
|
8
|
+
import type { AxmSkillCompatibilityUnavailable } from "@agentxm/cli-maintenance/official-skill/application";
|
|
9
|
+
import type { AxmSkillIncompatible } from "@agentxm/cli-maintenance/official-skill/domain";
|
|
9
10
|
declare const SkillDefinitionInvalid_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
11
|
readonly _tag: "SkillDefinitionInvalid";
|
|
11
12
|
} & Readonly<A>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { usableAcceptedCanonical } from "@agentxm/workspace-state";
|
|
2
|
+
import { LifecyclePostconditionViolated } from "../extensions/errors.js";
|
|
1
3
|
/**
|
|
2
4
|
* Skill extension manager service.
|
|
3
5
|
*
|
|
@@ -216,6 +218,45 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
|
|
|
216
218
|
return yield* isObservedInstalled(ws, "skill", target.name);
|
|
217
219
|
}),
|
|
218
220
|
materializeInstall,
|
|
221
|
+
acquireCanonical: ({ ref, force }) => Effect.gen(function* () {
|
|
222
|
+
const locked = yield* ws.getLockedSkill(ref.skill.name);
|
|
223
|
+
const materialized = yield* materializeSkillCanonical({
|
|
224
|
+
ref,
|
|
225
|
+
sanitizedName: sanitizeName(ref.skill.name),
|
|
226
|
+
baseDir,
|
|
227
|
+
layout: ws.layout,
|
|
228
|
+
reuse: {
|
|
229
|
+
force: force === true,
|
|
230
|
+
lockedVersion: ref.refType === "registry" ? acceptedRegistryVersionForRef(locked, ref) : undefined,
|
|
231
|
+
lockedTreeIntegrity: Option.isSome(locked) ? locked.value.treeIntegrity : undefined,
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
const sourceHash = ref.refType === "workspace"
|
|
235
|
+
? ref.sourceHash
|
|
236
|
+
: ref.refType === "registry"
|
|
237
|
+
? yield* computePackageContentHash(path.dirname(materialized.skillSrcPath))
|
|
238
|
+
: yield* computeSkillSourceHash(materialized.skillSrcPath);
|
|
239
|
+
return {
|
|
240
|
+
sourceHash: Option.some(sourceHash),
|
|
241
|
+
treeIntegrity: Option.fromUndefinedOr(materialized.treeIntegrity),
|
|
242
|
+
observation: { agents: [], targets: [] },
|
|
243
|
+
};
|
|
244
|
+
}),
|
|
245
|
+
materializeRetained: ({ target }) => Effect.gen(function* () {
|
|
246
|
+
const canonical = yield* usableAcceptedCanonical({
|
|
247
|
+
workspace: ws,
|
|
248
|
+
type: "skill",
|
|
249
|
+
name: target.name,
|
|
250
|
+
});
|
|
251
|
+
if (Option.isNone(canonical) || canonical.value.ref.type !== "skill") {
|
|
252
|
+
return yield* new LifecyclePostconditionViolated({
|
|
253
|
+
postcondition: "materialize-observable",
|
|
254
|
+
targetType: "skill",
|
|
255
|
+
targetName: target.name,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return yield* materializeInstall({ ref: canonical.value.ref });
|
|
259
|
+
}),
|
|
219
260
|
prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
|
|
220
261
|
workspace: ws,
|
|
221
262
|
type: "skill",
|
|
@@ -249,49 +290,7 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
|
|
|
249
290
|
}),
|
|
250
291
|
materializeUninstall,
|
|
251
292
|
materializeDeactivate,
|
|
252
|
-
|
|
253
|
-
const workspaceRelativeLocalSourcePath = ref.refType === "local"
|
|
254
|
-
? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
|
|
255
|
-
: Option.none();
|
|
256
|
-
if (ref.refType === "local" && Option.isNone(workspaceRelativeLocalSourcePath)) {
|
|
257
|
-
return yield* new SkillDefinitionInvalid({
|
|
258
|
-
detail: `Local skill source path must stay within the workspace root: ${ref.source.path}`,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
const sourceHash = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.sourceHash)));
|
|
262
|
-
const treeIntegrity = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity)));
|
|
263
|
-
if (ref.refType === "workspace") {
|
|
264
|
-
return yield* ws.setSkillEntry(ref.skill.name, {
|
|
265
|
-
source: "workspace",
|
|
266
|
-
enabled: true,
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
if (sourceHash === undefined || treeIntegrity === undefined) {
|
|
270
|
-
return yield* new SkillInstallStateMissing({
|
|
271
|
-
name: ref.skill.name,
|
|
272
|
-
kind: "content-identity",
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
const lockEntry = buildSkillLockEntry(ref, workspaceRelativeLocalSourcePath, sourceHash, treeIntegrity);
|
|
276
|
-
if (lockEntry === undefined) {
|
|
277
|
-
return yield* new SkillInstallStateMissing({
|
|
278
|
-
name: ref.skill.name,
|
|
279
|
-
kind: "external-resolution",
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
if (lockEntry.type === "registry") {
|
|
283
|
-
yield* validateExactResolvedVersion(`skills.${ref.skill.name}.resolvedVersion`, lockEntry.resolvedVersion);
|
|
284
|
-
}
|
|
285
|
-
return yield* ws.setSkill({
|
|
286
|
-
name: ref.skill.name,
|
|
287
|
-
lockEntry,
|
|
288
|
-
versionRange,
|
|
289
|
-
});
|
|
290
|
-
}),
|
|
291
|
-
removeSettingsEntry: ({ target }) => ws
|
|
292
|
-
.removeSkillFromSettings(target.name)
|
|
293
|
-
.pipe(Effect.withSpan("SkillManager.removeSettingsEntry")),
|
|
294
|
-
upsertLockfileEntry: Effect.fn("SkillManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
|
|
293
|
+
acceptedResolution: Effect.fn("SkillManager.acceptedResolution")(function* ({ ref, materialization, }) {
|
|
295
294
|
const workspaceRelativeLocalSourcePath = ref.refType === "local"
|
|
296
295
|
? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
|
|
297
296
|
: Option.none();
|
|
@@ -301,8 +300,7 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
|
|
|
301
300
|
});
|
|
302
301
|
}
|
|
303
302
|
if (ref.refType === "workspace") {
|
|
304
|
-
|
|
305
|
-
return;
|
|
303
|
+
return Option.none();
|
|
306
304
|
}
|
|
307
305
|
const sourceHash = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.sourceHash)));
|
|
308
306
|
const treeIntegrity = Option.getOrUndefined(materialization.pipe(Option.flatMap((facts) => facts.treeIntegrity)));
|
|
@@ -322,15 +320,9 @@ export const SkillManagerLive = Layer.effect(SkillManager, Effect.gen(function*
|
|
|
322
320
|
if (lockEntry.type === "registry") {
|
|
323
321
|
yield* validateExactResolvedVersion(`skills.${ref.skill.name}.resolvedVersion`, lockEntry.resolvedVersion);
|
|
324
322
|
}
|
|
325
|
-
return
|
|
326
|
-
name: ref.skill.name,
|
|
327
|
-
lockEntry,
|
|
328
|
-
versionRange: Option.none(),
|
|
329
|
-
});
|
|
323
|
+
return Option.some({ key: ref.skill.name, entry: lockEntry });
|
|
330
324
|
}),
|
|
331
|
-
|
|
332
|
-
.removeSkillLock(target.name)
|
|
333
|
-
.pipe(Effect.withSpan("SkillManager.removeLockfileEntry")),
|
|
325
|
+
withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
|
|
334
326
|
};
|
|
335
327
|
}));
|
|
336
328
|
// -----------------------------------------------------------------------------
|
|
@@ -35,10 +35,10 @@ export declare const materializeSkillCanonical: (args: {
|
|
|
35
35
|
}) => Effect.Effect<{
|
|
36
36
|
skillSrcPath: string & import("effect/Brand").Brand<"AbsolutePath">;
|
|
37
37
|
treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
38
|
-
}, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").PackageCopyFailed | import("@agentxm/
|
|
38
|
+
}, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").PackageCopyFailed | import("@agentxm/cli-maintenance/official-skill/application").AxmSkillCompatibilityUnavailable | import("@agentxm/cli-maintenance/official-skill/domain").AxmSkillIncompatible | import("@agentxm/workspace-state").MaterializedTreeInvalid | import("../extensions/canonical-directory.js").CanonicalDirectoryReplacementError, FileSystem.FileSystem | Path.Path> | Effect.Effect<{
|
|
39
39
|
skillSrcPath: string & import("effect/Brand").Brand<"AbsolutePath">;
|
|
40
40
|
treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
41
|
-
}, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").ArchiveIntegrityMismatch | import("@agentxm/
|
|
41
|
+
}, import("../index.ts").CanonicalPackageProbeFailed | import("../index.ts").ArchiveIntegrityMismatch | import("@agentxm/cli-maintenance/official-skill/application").AxmSkillCompatibilityUnavailable | import("@agentxm/cli-maintenance/official-skill/domain").AxmSkillIncompatible | import("@agentxm/workspace-state").MaterializedTreeInvalid | import("@agentxm/registry-client").RegistryClientFailure | import("../extensions/canonical-directory.js").CanonicalDirectoryReplacementError, FileSystem.FileSystem | Path.Path | import("effect/unstable/http/HttpClient").HttpClient> | Effect.Effect<MaterializedSkillCanonical, import("@agentxm/workspace-state").PathTraversalDetected | import("@agentxm/cli-maintenance/official-skill/application").AxmSkillCompatibilityUnavailable | import("@agentxm/cli-maintenance/official-skill/domain").AxmSkillIncompatible, FileSystem.FileSystem | Path.Path>;
|
|
42
42
|
export declare const ensureSkillAgentArtifact: (args: {
|
|
43
43
|
readonly canonicalSkillSrcPath: string;
|
|
44
44
|
readonly targetDir: string;
|
|
@@ -29,7 +29,11 @@ export declare const skillArtifactFromTargets: (args: {
|
|
|
29
29
|
readonly change: JobStepArtifact["change"];
|
|
30
30
|
readonly workspaceTargets?: ReadonlyArray<JobStepArtifactTarget>;
|
|
31
31
|
}) => Effect.Effect<{
|
|
32
|
-
targets?: JobStepArtifactTarget
|
|
32
|
+
targets?: (JobStepArtifactTarget | {
|
|
33
|
+
agentIds?: readonly string[];
|
|
34
|
+
path: string;
|
|
35
|
+
change: "created" | "updated" | "removed" | "unchanged";
|
|
36
|
+
})[];
|
|
33
37
|
path: string;
|
|
34
38
|
scope: "project" | "user";
|
|
35
39
|
agents: readonly string[];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { usableAcceptedCanonical } from "@agentxm/workspace-state";
|
|
2
|
+
import { LifecyclePostconditionViolated } from "../extensions/errors.js";
|
|
1
3
|
/**
|
|
2
4
|
* Subagent extension manager service.
|
|
3
5
|
*
|
|
@@ -633,6 +635,31 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
|
|
|
633
635
|
return yield* isObservedInstalled(ws, "subagent", target.name);
|
|
634
636
|
}),
|
|
635
637
|
materializeInstall,
|
|
638
|
+
acquireCanonical: ({ ref, force }) => Effect.gen(function* () {
|
|
639
|
+
const { sanitized, paths: { canonicalPath, subagentSrcPath }, } = getCanonicalPaths(ref);
|
|
640
|
+
const treeIntegrity = yield* materializeCanonical(ref, sanitized, canonicalPath, subagentSrcPath, force === true);
|
|
641
|
+
yield* readSubagentContent(subagentSrcPath, ref.subagent.name);
|
|
642
|
+
return {
|
|
643
|
+
sourceHash: Option.some(yield* computePackageContentHash(canonicalPath)),
|
|
644
|
+
treeIntegrity: Option.fromUndefinedOr(treeIntegrity),
|
|
645
|
+
observation: { agents: [], targets: [] },
|
|
646
|
+
};
|
|
647
|
+
}),
|
|
648
|
+
materializeRetained: ({ target }) => Effect.gen(function* () {
|
|
649
|
+
const canonical = yield* usableAcceptedCanonical({
|
|
650
|
+
workspace: ws,
|
|
651
|
+
type: "subagent",
|
|
652
|
+
name: target.name,
|
|
653
|
+
});
|
|
654
|
+
if (Option.isNone(canonical) || canonical.value.ref.type !== "subagent") {
|
|
655
|
+
return yield* new LifecyclePostconditionViolated({
|
|
656
|
+
postcondition: "materialize-observable",
|
|
657
|
+
targetType: "subagent",
|
|
658
|
+
targetName: target.name,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
return yield* materializeInstall({ ref: canonical.value.ref });
|
|
662
|
+
}),
|
|
636
663
|
prepareSourceTransition: ({ ref }) => prepareAcceptedCanonicalTransition({
|
|
637
664
|
workspace: ws,
|
|
638
665
|
type: "subagent",
|
|
@@ -651,7 +678,7 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
|
|
|
651
678
|
}),
|
|
652
679
|
materializeUninstall,
|
|
653
680
|
materializeDeactivate,
|
|
654
|
-
|
|
681
|
+
acceptedResolution: Effect.fn("SubagentManager.acceptedResolution")(function* ({ ref, materialization, }) {
|
|
655
682
|
const workspaceRelativeLocalSourcePath = ref.refType === "local"
|
|
656
683
|
? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
|
|
657
684
|
: Option.none();
|
|
@@ -660,50 +687,8 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
|
|
|
660
687
|
detail: `Local subagent source path must stay within the workspace root: ${ref.source.path}`,
|
|
661
688
|
});
|
|
662
689
|
}
|
|
663
|
-
const state = acquiredState(materialization);
|
|
664
690
|
if (ref.refType === "workspace") {
|
|
665
|
-
return
|
|
666
|
-
source: "workspace",
|
|
667
|
-
enabled: true,
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
|
-
if (state === undefined) {
|
|
671
|
-
return yield* new SubagentInstallStateMissing({
|
|
672
|
-
name: ref.subagent.name,
|
|
673
|
-
kind: "content-identity",
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
const lockEntry = buildSubagentLockEntry(ref, state.sourceHash, state.treeIntegrity, workspaceRelativeLocalSourcePath);
|
|
677
|
-
if (lockEntry === undefined) {
|
|
678
|
-
return yield* new SubagentInstallStateMissing({
|
|
679
|
-
name: ref.subagent.name,
|
|
680
|
-
kind: "external-resolution",
|
|
681
|
-
});
|
|
682
|
-
}
|
|
683
|
-
if (lockEntry.type === "registry") {
|
|
684
|
-
yield* validateExactResolvedVersion(`subagents.${ref.subagent.name}.resolvedVersion`, lockEntry.resolvedVersion);
|
|
685
|
-
}
|
|
686
|
-
return yield* ws.setSubagent({
|
|
687
|
-
name: ref.subagent.name,
|
|
688
|
-
lockEntry,
|
|
689
|
-
versionRange,
|
|
690
|
-
});
|
|
691
|
-
}),
|
|
692
|
-
removeSettingsEntry: ({ target }) => ws
|
|
693
|
-
.removeSubagentSettings(target.name)
|
|
694
|
-
.pipe(Effect.withSpan("SubagentManager.removeSettingsEntry")),
|
|
695
|
-
upsertLockfileEntry: Effect.fn("SubagentManager.upsertLockfileEntry")(function* ({ ref, materialization, }) {
|
|
696
|
-
const workspaceRelativeLocalSourcePath = ref.refType === "local"
|
|
697
|
-
? makeWorkspaceRelativeSourcePath(path, baseDir, ref.sourcePath ?? stripFileProtocol(ref.location))
|
|
698
|
-
: Option.none();
|
|
699
|
-
if (ref.refType === "local" && Option.isNone(workspaceRelativeLocalSourcePath)) {
|
|
700
|
-
return yield* new SubagentDefinitionInvalid({
|
|
701
|
-
detail: `Local subagent source path must stay within the workspace root: ${ref.source.path}`,
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
if (ref.refType === "workspace") {
|
|
705
|
-
yield* ws.removeSubagentLock(ref.subagent.name);
|
|
706
|
-
return;
|
|
691
|
+
return Option.none();
|
|
707
692
|
}
|
|
708
693
|
const state = acquiredState(materialization);
|
|
709
694
|
if (state === undefined) {
|
|
@@ -722,15 +707,9 @@ export const SubagentManagerLive = Layer.effect(SubagentManager, Effect.gen(func
|
|
|
722
707
|
if (lockEntry.type === "registry") {
|
|
723
708
|
yield* validateExactResolvedVersion(`subagents.${ref.subagent.name}.resolvedVersion`, lockEntry.resolvedVersion);
|
|
724
709
|
}
|
|
725
|
-
return
|
|
726
|
-
name: ref.subagent.name,
|
|
727
|
-
lockEntry,
|
|
728
|
-
versionRange: Option.none(),
|
|
729
|
-
});
|
|
710
|
+
return Option.some({ key: ref.subagent.name, entry: lockEntry });
|
|
730
711
|
}),
|
|
731
|
-
|
|
732
|
-
.removeSubagentLock(target.name)
|
|
733
|
-
.pipe(Effect.withSpan("SubagentManager.removeLockfileEntry")),
|
|
712
|
+
withdrawnResolutionKeys: ({ target }) => Effect.succeed([target.name]),
|
|
734
713
|
};
|
|
735
714
|
}));
|
|
736
715
|
//# sourceMappingURL=manager.js.map
|